-
Notifications
You must be signed in to change notification settings - Fork 0
/
adb.json
1 lines (1 loc) · 178 KB
/
adb.json
1
{"meta":{"version":1,"warehouse":"4.0.2"},"models":{"Asset":[{"_id":"node_modules/hexo-theme-landscape/source/css/style.styl","path":"css/style.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/fancybox/jquery.fancybox.min.js","path":"fancybox/jquery.fancybox.min.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/js/jquery-3.4.1.min.js","path":"js/jquery-3.4.1.min.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/js/script.js","path":"js/script.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/fancybox/jquery.fancybox.min.css","path":"fancybox/jquery.fancybox.min.css","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/FontAwesome.otf","path":"css/fonts/FontAwesome.otf","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.eot","path":"css/fonts/fontawesome-webfont.eot","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.svg","path":"css/fonts/fontawesome-webfont.svg","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.ttf","path":"css/fonts/fontawesome-webfont.ttf","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.woff","path":"css/fonts/fontawesome-webfont.woff","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.woff2","path":"css/fonts/fontawesome-webfont.woff2","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-landscape/source/css/images/banner.jpg","path":"css/images/banner.jpg","modified":0,"renderable":1}],"Cache":[{"_id":"source/_posts/hello-world.md","hash":"7d98d6592de80fdcd2949bd7401cec12afd98cdf","modified":1677417235402},{"_id":"node_modules/hexo-theme-landscape/LICENSE","hash":"c480fce396b23997ee23cc535518ffaaf7f458f8","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/README.md","hash":"d2772ece6d4422ccdaa0359c3e07588834044052","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/_config.yml","hash":"b608c1f1322760dce9805285a602a95832730a2e","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/package.json","hash":"9a94875cbf4c27fbe2e63da0496242addc6d2876","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/archive.ejs","hash":"2703b07cc8ac64ae46d1d263f4653013c7e1666b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/category.ejs","hash":"765426a9c8236828dc34759e604cc2c52292835a","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/index.ejs","hash":"aa1b4456907bdb43e629be3931547e2d29ac58c8","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/layout.ejs","hash":"0d1765036e4874500e68256fedb7470e96eeb6ee","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/page.ejs","hash":"7d80e4e36b14d30a7cd2ac1f61376d9ebf264e8b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/en.yml","hash":"3083f319b352d21d80fc5e20113ddf27889c9d11","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/de.yml","hash":"3ebf0775abbee928c8d7bda943c191d166ded0d3","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/post.ejs","hash":"7d80e4e36b14d30a7cd2ac1f61376d9ebf264e8b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/tag.ejs","hash":"eaa7b4ccb2ca7befb90142e4e68995fb1ea68b2e","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/fr.yml","hash":"415e1c580ced8e4ce20b3b0aeedc3610341c76fb","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/es.yml","hash":"76edb1171b86532ef12cfd15f5f2c1ac3949f061","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/hu.yml","hash":"284d557130bf54a74e7dcef9d42096130e4d9550","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/it.yml","hash":"89b7d91306b2c1a0f3ac023b657bf974f798a1e8","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/ja.yml","hash":"a73e1b9c80fd6e930e2628b393bfe3fb716a21a9","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/ko.yml","hash":"881d6a0a101706e0452af81c580218e0bfddd9cf","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/nl.yml","hash":"12ed59faba1fc4e8cdd1d42ab55ef518dde8039c","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/ru.yml","hash":"4fda301bbd8b39f2c714e2c934eccc4b27c0a2b0","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/tr.yml","hash":"a1cdbfa17682d7a971de8ab8588bf57c74224b5b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/zh-CN.yml","hash":"1efd95774f401c80193eac6ee3f1794bfe93dc5a","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/mn.yml","hash":"2e7523951072a9403ead3840ad823edd1084c116","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/zh-TW.yml","hash":"53ce3000c5f767759c7d2c4efcaa9049788599c3","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/scripts/fancybox.js","hash":"c857d7a5e4a5d71c743a009c5932bf84229db428","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/after-footer.ejs","hash":"414914ebb159fac1922b056b905e570ac7521925","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/pt.yml","hash":"57d07b75d434fbfc33b0ddb543021cb5f53318a8","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/archive-post.ejs","hash":"c7a71425a946d05414c069ec91811b5c09a92c47","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/article.ejs","hash":"dfd555c00e85ffc4207c88968d12b219c1f086ec","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/archive.ejs","hash":"7cb70a7a54f8c7ae49b10d1f37c0a9b74eab8826","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/footer.ejs","hash":"3656eb692254346671abc03cb3ba1459829e0dce","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/languages/no.yml","hash":"965a171e70347215ec726952e63f5b47930931ef","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/gauges-analytics.ejs","hash":"21a1e2a3907d1a3dad1cd0ab855fe6735f233c74","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/google-analytics.ejs","hash":"2ea7442ea1e1a8ab4e41e26c563f58413b59a3d0","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/head.ejs","hash":"f215d92a882247a7cc5ea80b241bedfcec0ea6ca","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/mobile-nav.ejs","hash":"e952a532dfc583930a666b9d4479c32d4a84b44e","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/sidebar.ejs","hash":"930da35cc2d447a92e5ee8f835735e6fd2232469","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_widget/archive.ejs","hash":"beb4a86fcc82a9bdda9289b59db5a1988918bec3","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/header.ejs","hash":"c1acd247e14588cdf101a69460cb8319c18cd078","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_widget/category.ejs","hash":"dd1e5af3c6af3f5d6c85dfd5ca1766faed6a0b05","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_widget/recent_posts.ejs","hash":"60c4b012dcc656438ff59997e60367e5a21ab746","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_widget/tag.ejs","hash":"2de380865df9ab5f577f7d3bcadf44261eb5faae","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_widget/tagcloud.ejs","hash":"b4a2079101643f63993dcdb32925c9b071763b46","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_extend.styl","hash":"222fbe6d222531d61c1ef0f868c90f747b1c2ced","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_variables.styl","hash":"581b0cbefdaa5f894922133989dd2d3bf71ded79","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/style.styl","hash":"9c451e5efd72c5bb8b56e8c2b94be731e99db05b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/js/script.js","hash":"998ed4c5b147e1299bf62beebf33514474f28112","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/fancybox/jquery.fancybox.min.css","hash":"1be9b79be02a1cfc5d96c4a5e0feb8f472babd95","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/category.ejs","hash":"c6bcd0e04271ffca81da25bcff5adf3d46f02fc0","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/date.ejs","hash":"f1458584b679545830b75bef2526e2f3eb931045","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/gallery.ejs","hash":"3d9d81a3c693ff2378ef06ddb6810254e509de5b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/tag.ejs","hash":"2fcb0bf9c8847a644167a27824c9bb19ac74dd14","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/nav.ejs","hash":"16a904de7bceccbb36b4267565f2215704db2880","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/layout/_partial/post/title.ejs","hash":"4d7e62574ddf46de9b41605fe3140d77b5ddb26d","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/archive.styl","hash":"db15f5677dc68f1730e82190bab69c24611ca292","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/article.styl","hash":"80759482d07063c091e940f964a1cf6693d3d406","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/comment.styl","hash":"79d280d8d203abb3bd933ca9b8e38c78ec684987","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/header.styl","hash":"85ab11e082f4dd86dde72bed653d57ec5381f30c","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/footer.styl","hash":"e35a060b8512031048919709a8e7b1ec0e40bc1b","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/highlight.styl","hash":"bf4e7be1968dad495b04e83c95eac14c4d0ad7c0","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/mobile.styl","hash":"a399cf9e1e1cec3e4269066e2948d7ae5854d745","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/sidebar-aside.styl","hash":"890349df5145abf46ce7712010c89237900b3713","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/sidebar-bottom.styl","hash":"8fd4f30d319542babfd31f087ddbac550f000a8a","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_partial/sidebar.styl","hash":"404ec059dc674a48b9ab89cd83f258dec4dcb24d","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_util/grid.styl","hash":"0bf55ee5d09f193e249083602ac5fcdb1e571aed","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/_util/mixin.styl","hash":"44f32767d9fd3c1c08a60d91f181ee53c8f0dbb3","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/js/jquery-3.4.1.min.js","hash":"88523924351bac0b5d560fe0c5781e2556e7693d","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/fancybox/jquery.fancybox.min.js","hash":"6181412e73966696d08e1e5b1243a572d0f22ba6","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.woff2","hash":"d6f48cba7d076fb6f2fd6ba993a75b9dc1ecbf0c","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.woff","hash":"28b782240b3e76db824e12c02754a9731a167527","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/FontAwesome.otf","hash":"048707bc52ac4b6563aaa383bfe8660a0ddc908c","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.eot","hash":"d980c2ce873dc43af460d4d572d441304499f400","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.ttf","hash":"13b1eab65a983c7a73bc7997c479d66943f7c6cb","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/images/banner.jpg","hash":"f44aa591089fcb3ec79770a1e102fd3289a7c6a6","modified":1677417270273},{"_id":"node_modules/hexo-theme-landscape/source/css/fonts/fontawesome-webfont.svg","hash":"98a8aa5cf7d62c2eff5f07ede8d844b874ef06ed","modified":1677417270273},{"_id":"source/_posts/stm32/stm32-with-swd.md","hash":"a34f9a3fb4b438baf3b2b5b06df09a2f2bec7ebe","modified":1677417476249},{"_id":"source/_posts/stm32/stm32-with-swd/image-20200926203922007.png","hash":"723ce1d01ba8f307dfd7e1155119516de6881af4","modified":1630555506000},{"_id":"source/_drafts/hello-world.md","hash":"7d98d6592de80fdcd2949bd7401cec12afd98cdf","modified":1677417235402},{"_id":"source/_posts/charset-clion-msvc.md","hash":"56cf3a845a900a072141378eb303999ce32a16ca","modified":1630555506000},{"_id":"source/_posts/dalao.md","hash":"f4f966370bd29b689554ca338a63a79f1dbbe944","modified":1630555506000},{"_id":"source/_posts/github-action-hexo-gen.md","hash":"a48c7283da42149b8669ad4db1c43c5cfac4505d","modified":1630555506000},{"_id":"source/_posts/gradle-execute-jar.md","hash":"f2cac5537ec6bc97476aaa89d9b3c7ce8fa26e78","modified":1630555506000},{"_id":"source/_posts/awsl.md","hash":"504792f5fd6d98693640a405a754165dd3320c2d","modified":1630555506000},{"_id":"source/_posts/hello.md","hash":"fca25cb2714628f739ac0a860ca748b7da354c90","modified":1630555506000},{"_id":"source/_posts/kotlin-kapt-note.md","hash":"84dcdbd116d7e61e9dabf37393e6ff4038f6d74e","modified":1630555506000},{"_id":"source/_posts/pgpkey.md","hash":"32771a1e4f52c604a5d0371665aff3a5c64f6b17","modified":1630555506000},{"_id":"source/_posts/some-of-coroutine-suspend-function.md","hash":"d6fbd2f4de08542b682131a58ee3108e6c13d314","modified":1630555506000},{"_id":"source/_posts/use-pgp-with-git-on-windows.md","hash":"ea3adcf46060b634d5e16369c051d2a54c054a96","modified":1630555506000},{"_id":"source/_posts/use-shadow-gradle-plugin-gen-fatjar.md","hash":"5c7fcc87277c53fb78b6845ed5244aba50734478","modified":1630555506000},{"_id":"source/_posts/stm32-with-swd/image-20200926203922007.png","hash":"723ce1d01ba8f307dfd7e1155119516de6881af4","modified":1630555506000},{"_id":"source/_posts/stm32-with-swd.md","hash":"011c51fc95ea82129fad06f9ffb7f56afffbdd6f","modified":1677418071823},{"_id":"source/_posts/test-image.md","hash":"750f52811805615d6adb5da510e18b9918e1a404","modified":1677418012529}],"Category":[],"Data":[],"Page":[],"Post":[{"title":"iseki根本不会写blog呢","date":"2020-04-21T15:33:10.000Z","updated":"2020-04-21T15:33:10.000Z","_content":"iseki 哪里会写博客呢…连什么是博客都说不清楚…只能时不时发发牢骚了…人逐渐的婆婆妈妈…愈发变得无聊…\n\n\n再看看前面的路…不知该干什么,也不知该走向何方呢。\n","source":"_posts/awsl.md","raw":"---\ntitle: iseki根本不会写blog呢\ndate: 2020-04-21 23:33:10\nupdated: 2020-04-21 23:33:10\ntags:\n---\niseki 哪里会写博客呢…连什么是博客都说不清楚…只能时不时发发牢骚了…人逐渐的婆婆妈妈…愈发变得无聊…\n\n\n再看看前面的路…不知该干什么,也不知该走向何方呢。\n","slug":"awsl","published":1,"_id":"clelf1duq0002o8uz5o5w948p","comments":1,"layout":"post","photos":[],"link":"","content":"<p>iseki 哪里会写博客呢…连什么是博客都说不清楚…只能时不时发发牢骚了…人逐渐的婆婆妈妈…愈发变得无聊…</p>\n<p>再看看前面的路…不知该干什么,也不知该走向何方呢。</p>\n","site":{"data":{}},"excerpt":"","more":"<p>iseki 哪里会写博客呢…连什么是博客都说不清楚…只能时不时发发牢骚了…人逐渐的婆婆妈妈…愈发变得无聊…</p>\n<p>再看看前面的路…不知该干什么,也不知该走向何方呢。</p>\n"},{"date":"2020-05-31T13:00:00.000Z","updated":"2020-05-31T13:00:00.000Z","title":"解决 CLion + MSVC 下的字符编码问题","_content":"\n# 解决 CLion + MSVC 下的字符编码问题\n\n第一次这么用,上来字符编码就炸了,不出意外 log 中会出现如下内容\n\n```\nwarning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失\n```\n\n然后就是诡异的编译失败语法错误,比如换行符、分号等等\n\n原因是 CLion 默认使用 UTF-8 编码,MSVC 继承了 MS 家族的一贯传统,除非明确指定否则要么 UTF-8 with BOM 要么当前代码页。\n\n解决办法也简单,加上命令行开关就行了: `/utf-8` 或者 `source-charset:utf-8 /execution-charset:utf-8` [参见MSVC文档>>](https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8)\n\n默认创建的项目是 CMake 的,在 `CMakeList.txt` 中加入如下内容即可\n\n```cmake\nadd_compile_options(\"$<$<C_COMPILER_ID:MSVC>:/utf-8>\")\nadd_compile_options(\"$<$<CXX_COMPILER_ID:MSVC>:/utf-8>\")\n```\n\n括号中表达式语法具体参见 [cmake-generator-expressions(7)](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7))","source":"_posts/charset-clion-msvc.md","raw":"---\ndate: 2020/5/31 21:00:00\nupdated: 2020/5/31 21:00:00\ntitle: 解决 CLion + MSVC 下的字符编码问题\n\n---\n\n# 解决 CLion + MSVC 下的字符编码问题\n\n第一次这么用,上来字符编码就炸了,不出意外 log 中会出现如下内容\n\n```\nwarning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失\n```\n\n然后就是诡异的编译失败语法错误,比如换行符、分号等等\n\n原因是 CLion 默认使用 UTF-8 编码,MSVC 继承了 MS 家族的一贯传统,除非明确指定否则要么 UTF-8 with BOM 要么当前代码页。\n\n解决办法也简单,加上命令行开关就行了: `/utf-8` 或者 `source-charset:utf-8 /execution-charset:utf-8` [参见MSVC文档>>](https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8)\n\n默认创建的项目是 CMake 的,在 `CMakeList.txt` 中加入如下内容即可\n\n```cmake\nadd_compile_options(\"$<$<C_COMPILER_ID:MSVC>:/utf-8>\")\nadd_compile_options(\"$<$<CXX_COMPILER_ID:MSVC>:/utf-8>\")\n```\n\n括号中表达式语法具体参见 [cmake-generator-expressions(7)](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7))","slug":"charset-clion-msvc","published":1,"_id":"clelf1dur0003o8uz8vr6d1gx","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"解决-CLion-MSVC-下的字符编码问题\"><a href=\"#解决-CLion-MSVC-下的字符编码问题\" class=\"headerlink\" title=\"解决 CLion + MSVC 下的字符编码问题\"></a>解决 CLion + MSVC 下的字符编码问题</h1><p>第一次这么用,上来字符编码就炸了,不出意外 log 中会出现如下内容</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失</span><br></pre></td></tr></table></figure>\n\n<p>然后就是诡异的编译失败语法错误,比如换行符、分号等等</p>\n<p>原因是 CLion 默认使用 UTF-8 编码,MSVC 继承了 MS 家族的一贯传统,除非明确指定否则要么 UTF-8 with BOM 要么当前代码页。</p>\n<p>解决办法也简单,加上命令行开关就行了: <code>/utf-8</code> 或者 <code>source-charset:utf-8 /execution-charset:utf-8</code> <a href=\"https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8\">参见MSVC文档>></a></p>\n<p>默认创建的项目是 CMake 的,在 <code>CMakeList.txt</code> 中加入如下内容即可</p>\n<figure class=\"highlight cmake\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">add_compile_options</span>(<span class=\"string\">"$<$<C_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br><span class=\"line\"><span class=\"keyword\">add_compile_options</span>(<span class=\"string\">"$<$<CXX_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br></pre></td></tr></table></figure>\n\n<p>括号中表达式语法具体参见 <a href=\"https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7)\">cmake-generator-expressions(7)</a></p>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"解决-CLion-MSVC-下的字符编码问题\"><a href=\"#解决-CLion-MSVC-下的字符编码问题\" class=\"headerlink\" title=\"解决 CLion + MSVC 下的字符编码问题\"></a>解决 CLion + MSVC 下的字符编码问题</h1><p>第一次这么用,上来字符编码就炸了,不出意外 log 中会出现如下内容</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失</span><br></pre></td></tr></table></figure>\n\n<p>然后就是诡异的编译失败语法错误,比如换行符、分号等等</p>\n<p>原因是 CLion 默认使用 UTF-8 编码,MSVC 继承了 MS 家族的一贯传统,除非明确指定否则要么 UTF-8 with BOM 要么当前代码页。</p>\n<p>解决办法也简单,加上命令行开关就行了: <code>/utf-8</code> 或者 <code>source-charset:utf-8 /execution-charset:utf-8</code> <a href=\"https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8\">参见MSVC文档>></a></p>\n<p>默认创建的项目是 CMake 的,在 <code>CMakeList.txt</code> 中加入如下内容即可</p>\n<figure class=\"highlight cmake\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">add_compile_options</span>(<span class=\"string\">"$<$<C_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br><span class=\"line\"><span class=\"keyword\">add_compile_options</span>(<span class=\"string\">"$<$<CXX_COMPILER_ID:MSVC>:/utf-8>"</span>)</span><br></pre></td></tr></table></figure>\n\n<p>括号中表达式语法具体参见 <a href=\"https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7)\">cmake-generator-expressions(7)</a></p>\n"},{"title":"Gradle 里执行 Jar 的几种办法","date":"2020-04-11T12:44:00.000Z","updated":"2020-04-11T12:44:00.000Z","_content":"> Gradle 这个东西真是让人头大······ 这里权当留个笔记备忘了,改日要好好学习下 Gradle\n\n之前只用过 `application` 插件,结果用了 Kotlin MPP 后那个插件似乎失效了,虽然应该有办法通过手动配置继续使用那个插件,但是考虑到自己完全不熟悉 Gradle 还是不多折腾了···\n\n以下内容来自 StackOverflow......\n\n```kotlin\ntasks.create(\"execute\") {\n dependsOn(tasks.getByName(\"jvmJar\"))\n doLast {\n javaexec {\n this.main = \"-jar\"\n val file = File(buildDir.absolutePath + \"/libs/project-jvm-0.0.1.jar\")\n println(\"Execute Jar: \" + file.absolutePath)\n this.args(file.absolutePath)\n }\n }\n}\n```\n要注意的是要写好 `manifest` 的 `Main-Class` 还要依赖的问题,最粗暴的办法无非就是打包成 Fat-Jar (x\n\n","source":"_posts/gradle-execute-jar.md","raw":"---\ntitle: Gradle 里执行 Jar 的几种办法\ndate: 2020-04-11 20:44:00\nupdated: 2020-04-11 20:44:00\ntags: [gradle]\n---\n> Gradle 这个东西真是让人头大······ 这里权当留个笔记备忘了,改日要好好学习下 Gradle\n\n之前只用过 `application` 插件,结果用了 Kotlin MPP 后那个插件似乎失效了,虽然应该有办法通过手动配置继续使用那个插件,但是考虑到自己完全不熟悉 Gradle 还是不多折腾了···\n\n以下内容来自 StackOverflow......\n\n```kotlin\ntasks.create(\"execute\") {\n dependsOn(tasks.getByName(\"jvmJar\"))\n doLast {\n javaexec {\n this.main = \"-jar\"\n val file = File(buildDir.absolutePath + \"/libs/project-jvm-0.0.1.jar\")\n println(\"Execute Jar: \" + file.absolutePath)\n this.args(file.absolutePath)\n }\n }\n}\n```\n要注意的是要写好 `manifest` 的 `Main-Class` 还要依赖的问题,最粗暴的办法无非就是打包成 Fat-Jar (x\n\n","slug":"gradle-execute-jar","published":1,"_id":"clelf1dv80004o8uzd2dp5blj","comments":1,"layout":"post","photos":[],"link":"","content":"<blockquote>\n<p>Gradle 这个东西真是让人头大······ 这里权当留个笔记备忘了,改日要好好学习下 Gradle</p>\n</blockquote>\n<p>之前只用过 <code>application</code> 插件,结果用了 Kotlin MPP 后那个插件似乎失效了,虽然应该有办法通过手动配置继续使用那个插件,但是考虑到自己完全不熟悉 Gradle 还是不多折腾了···</p>\n<p>以下内容来自 StackOverflow……</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">tasks.create(<span class=\"string\">"execute"</span>) {</span><br><span class=\"line\"> dependsOn(tasks.getByName(<span class=\"string\">"jvmJar"</span>))</span><br><span class=\"line\"> doLast {</span><br><span class=\"line\"> javaexec {</span><br><span class=\"line\"> <span class=\"keyword\">this</span>.main = <span class=\"string\">"-jar"</span></span><br><span class=\"line\"> <span class=\"keyword\">val</span> file = File(buildDir.absolutePath + <span class=\"string\">"/libs/project-jvm-0.0.1.jar"</span>)</span><br><span class=\"line\"> println(<span class=\"string\">"Execute Jar: "</span> + file.absolutePath)</span><br><span class=\"line\"> <span class=\"keyword\">this</span>.args(file.absolutePath)</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>要注意的是要写好 <code>manifest</code> 的 <code>Main-Class</code> 还要依赖的问题,最粗暴的办法无非就是打包成 Fat-Jar (x</p>\n","site":{"data":{}},"excerpt":"","more":"<blockquote>\n<p>Gradle 这个东西真是让人头大······ 这里权当留个笔记备忘了,改日要好好学习下 Gradle</p>\n</blockquote>\n<p>之前只用过 <code>application</code> 插件,结果用了 Kotlin MPP 后那个插件似乎失效了,虽然应该有办法通过手动配置继续使用那个插件,但是考虑到自己完全不熟悉 Gradle 还是不多折腾了···</p>\n<p>以下内容来自 StackOverflow……</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">tasks.create(<span class=\"string\">"execute"</span>) {</span><br><span class=\"line\"> dependsOn(tasks.getByName(<span class=\"string\">"jvmJar"</span>))</span><br><span class=\"line\"> doLast {</span><br><span class=\"line\"> javaexec {</span><br><span class=\"line\"> <span class=\"keyword\">this</span>.main = <span class=\"string\">"-jar"</span></span><br><span class=\"line\"> <span class=\"keyword\">val</span> file = File(buildDir.absolutePath + <span class=\"string\">"/libs/project-jvm-0.0.1.jar"</span>)</span><br><span class=\"line\"> println(<span class=\"string\">"Execute Jar: "</span> + file.absolutePath)</span><br><span class=\"line\"> <span class=\"keyword\">this</span>.args(file.absolutePath)</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>要注意的是要写好 <code>manifest</code> 的 <code>Main-Class</code> 还要依赖的问题,最粗暴的办法无非就是打包成 Fat-Jar (x</p>\n"},{"date":"2019-10-17T15:30:00.000Z","updated":"2019-10-17T15:30:00.000Z","title":"这里是iseki的笔记本呢","_content":"\n我也不会写什么blog,那么,这里就当作一个笔记本用吧,毕竟有些东西,好不容易搞明白,忘记了还是很麻烦的呢。\n要是能借机会帮到其他人,我也是很高兴的呢。\n\n这里用Hexo驱动,Github 托管 + Cloudflare CDN 外加一份开源的主题,自己凑凑合合写个Github Action workflow(其实没有也无所谓啊),就算差不多能用了。\n首页的链接嘛,基本都点不开(x\n\n那么,就先这样了,最后,忘了说一句,既然你来了,那说明咱俩有缘啊(x\n\n总之,欢迎光临了)x\n\n满口胡话的iseki\n\n2019.10.17","source":"_posts/hello.md","raw":"---\ndate: 2019-10-17 23:30:00\nupdated: 2019-10-17 23:30:00\ntitle: 这里是iseki的笔记本呢\ntags: [pin,text]\n---\n\n我也不会写什么blog,那么,这里就当作一个笔记本用吧,毕竟有些东西,好不容易搞明白,忘记了还是很麻烦的呢。\n要是能借机会帮到其他人,我也是很高兴的呢。\n\n这里用Hexo驱动,Github 托管 + Cloudflare CDN 外加一份开源的主题,自己凑凑合合写个Github Action workflow(其实没有也无所谓啊),就算差不多能用了。\n首页的链接嘛,基本都点不开(x\n\n那么,就先这样了,最后,忘了说一句,既然你来了,那说明咱俩有缘啊(x\n\n总之,欢迎光临了)x\n\n满口胡话的iseki\n\n2019.10.17","slug":"hello","published":1,"_id":"clelf1dv90005o8uzfaqb4oyd","comments":1,"layout":"post","photos":[],"link":"","content":"<p>我也不会写什么blog,那么,这里就当作一个笔记本用吧,毕竟有些东西,好不容易搞明白,忘记了还是很麻烦的呢。<br>要是能借机会帮到其他人,我也是很高兴的呢。</p>\n<p>这里用Hexo驱动,Github 托管 + Cloudflare CDN 外加一份开源的主题,自己凑凑合合写个Github Action workflow(其实没有也无所谓啊),就算差不多能用了。<br>首页的链接嘛,基本都点不开(x</p>\n<p>那么,就先这样了,最后,忘了说一句,既然你来了,那说明咱俩有缘啊(x</p>\n<p>总之,欢迎光临了)x</p>\n<p>满口胡话的iseki</p>\n<p>2019.10.17</p>\n","site":{"data":{}},"excerpt":"","more":"<p>我也不会写什么blog,那么,这里就当作一个笔记本用吧,毕竟有些东西,好不容易搞明白,忘记了还是很麻烦的呢。<br>要是能借机会帮到其他人,我也是很高兴的呢。</p>\n<p>这里用Hexo驱动,Github 托管 + Cloudflare CDN 外加一份开源的主题,自己凑凑合合写个Github Action workflow(其实没有也无所谓啊),就算差不多能用了。<br>首页的链接嘛,基本都点不开(x</p>\n<p>那么,就先这样了,最后,忘了说一句,既然你来了,那说明咱俩有缘啊(x</p>\n<p>总之,欢迎光临了)x</p>\n<p>满口胡话的iseki</p>\n<p>2019.10.17</p>\n"},{"title":"在GitHub Action里设置 Hexo gen 的折腾笔记","date":"2019-10-17T14:44:00.000Z","updated":"2019-10-17T14:44:00.000Z","_content":"\n不想阅读Github Action厚重的文档,用预配置好的NPM Action折腾了半天,终以失败告终。由于不熟悉NPM和Node.js,最后爆出的错误摸不到头脑,就此作罢。\n\n寻找另一个方法,在 `https://github.com/user/repo/actions/new` 中选择了跳过,自己设置一个空白的Workflow。\n\n1. 为了避免Action重新推送仓库后循环触发Action(不知Github有没有对这种情况进行特殊处理)添加路径过滤器,仅当 `/source` 目录存在更新时才触发 Workflow\n\n2. 在仓库的 `Settings->Deploy keys` 里设置Github Action push时使用的SSH公钥,并赋予写权限,`Settings->Secrets` 里设置私钥的 Base64 编码。\n私钥会通过环境变量传入Action的shell,`base64 -d` 即可解码,base64编码是为了避免潜在的回车换行符问题(环境变量里出现的换行符似乎不能正确地写入文件)\n\n3. 注意工作目录的问题,别瞎跑,目录会丢掉的\n\n4. `~/.ssh/id_rsa` 文件注意设定权限 `0600` 默认的权限过于宽松,SSH会不读取。\n\n5. `~/.ssh/config` 里需写入 \n```\nHost *\n StrictHostKeyChecking no\n```\n否则可能会弹出要求确认SSH fingerprint的交互消息。\n\n6. 记得设定 `git config --global user.name/email` 否则无法提交\n7. 如果使用了自定义的域名,注意 `CNAME` 文件是否在 `hexo clean` 后被删除,可能需要自己写回去。\n9. 注意部分Hexo主题可能以 git submodule 方式引入, Github Action 克隆仓库时不会自动克隆子模块,导致生成的所有页面空白,Hexo只会给出警告而不是错误。\n\n\n### 附上自己写的workflow(糊成一坨,凑合能用)\n\n```yaml\nname: Generate Hexo\n\non:\n push: \n paths: \n - 'source/**'\n\njobs: \n build: \n name: Refresh\n runs-on: ubuntu-latest\n steps:\n - name: Install Node.js and NPM\n run: |\n sudo apt-get install curl -y\n curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -\n sudo apt-get install nodejs -y\n echo '=====Show NPM version====='\n npm -v\n echo '=====Show Node.js version====='\n node -v\n - name: Install Hexo\n run: |\n sudo npm install -g hexo-cli\n echo '=====Show HEXO version====='\n hexo -v\n - name: Prepare Key and SSH config\n run: |\n mkdir ~/.ssh\n echo $DEPLOY_PRIVKEY | base64 -d > ~/.ssh/id_rsa\n chmod 0600 ~/.ssh/id_rsa\n echo 'Host *' >> ~/.ssh/config\n echo ' StrictHostKeyChecking no' >> ~/.ssh/config\n chmod 0600 ~/.ssh/config\n env: \n DEPLOY_PRIVKEY: ${{ secrets.DEPLOY_PRIVKEY }}\n - name: Clone git repo\n run: |\n cd ~\n echo '=====Show work path====='\n pwd\n git clone [email protected]:cpdyj/blog.git\n cd blog\n ls\n echo '=====Show work path====='\n pwd\n cat ./package.json\n npm install\n npm audit fix\n hexo clean\n hexo g\n echo \"blog.iseki.space\" > ./docs/CNAME\n git config --global user.name \"User name\"\n git config --global user.email \"[email protected]\"\n git add docs\n git commit -am \"Auto generate on Github Action at `date`\"\n git push\n```\n","source":"_posts/github-action-hexo-gen.md","raw":"---\ntitle: 在GitHub Action里设置 Hexo gen 的折腾笔记\ndate: 2019-10-17 22:44:00\nupdated: 2019-10-17 22:44:00\ntags: [github,action,nodejs,npm,hexo]\n---\n\n不想阅读Github Action厚重的文档,用预配置好的NPM Action折腾了半天,终以失败告终。由于不熟悉NPM和Node.js,最后爆出的错误摸不到头脑,就此作罢。\n\n寻找另一个方法,在 `https://github.com/user/repo/actions/new` 中选择了跳过,自己设置一个空白的Workflow。\n\n1. 为了避免Action重新推送仓库后循环触发Action(不知Github有没有对这种情况进行特殊处理)添加路径过滤器,仅当 `/source` 目录存在更新时才触发 Workflow\n\n2. 在仓库的 `Settings->Deploy keys` 里设置Github Action push时使用的SSH公钥,并赋予写权限,`Settings->Secrets` 里设置私钥的 Base64 编码。\n私钥会通过环境变量传入Action的shell,`base64 -d` 即可解码,base64编码是为了避免潜在的回车换行符问题(环境变量里出现的换行符似乎不能正确地写入文件)\n\n3. 注意工作目录的问题,别瞎跑,目录会丢掉的\n\n4. `~/.ssh/id_rsa` 文件注意设定权限 `0600` 默认的权限过于宽松,SSH会不读取。\n\n5. `~/.ssh/config` 里需写入 \n```\nHost *\n StrictHostKeyChecking no\n```\n否则可能会弹出要求确认SSH fingerprint的交互消息。\n\n6. 记得设定 `git config --global user.name/email` 否则无法提交\n7. 如果使用了自定义的域名,注意 `CNAME` 文件是否在 `hexo clean` 后被删除,可能需要自己写回去。\n9. 注意部分Hexo主题可能以 git submodule 方式引入, Github Action 克隆仓库时不会自动克隆子模块,导致生成的所有页面空白,Hexo只会给出警告而不是错误。\n\n\n### 附上自己写的workflow(糊成一坨,凑合能用)\n\n```yaml\nname: Generate Hexo\n\non:\n push: \n paths: \n - 'source/**'\n\njobs: \n build: \n name: Refresh\n runs-on: ubuntu-latest\n steps:\n - name: Install Node.js and NPM\n run: |\n sudo apt-get install curl -y\n curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -\n sudo apt-get install nodejs -y\n echo '=====Show NPM version====='\n npm -v\n echo '=====Show Node.js version====='\n node -v\n - name: Install Hexo\n run: |\n sudo npm install -g hexo-cli\n echo '=====Show HEXO version====='\n hexo -v\n - name: Prepare Key and SSH config\n run: |\n mkdir ~/.ssh\n echo $DEPLOY_PRIVKEY | base64 -d > ~/.ssh/id_rsa\n chmod 0600 ~/.ssh/id_rsa\n echo 'Host *' >> ~/.ssh/config\n echo ' StrictHostKeyChecking no' >> ~/.ssh/config\n chmod 0600 ~/.ssh/config\n env: \n DEPLOY_PRIVKEY: ${{ secrets.DEPLOY_PRIVKEY }}\n - name: Clone git repo\n run: |\n cd ~\n echo '=====Show work path====='\n pwd\n git clone [email protected]:cpdyj/blog.git\n cd blog\n ls\n echo '=====Show work path====='\n pwd\n cat ./package.json\n npm install\n npm audit fix\n hexo clean\n hexo g\n echo \"blog.iseki.space\" > ./docs/CNAME\n git config --global user.name \"User name\"\n git config --global user.email \"[email protected]\"\n git add docs\n git commit -am \"Auto generate on Github Action at `date`\"\n git push\n```\n","slug":"github-action-hexo-gen","published":1,"_id":"clelf1dvd000co8uz3ja6fqv5","comments":1,"layout":"post","photos":[],"link":"","content":"<p>不想阅读Github Action厚重的文档,用预配置好的NPM Action折腾了半天,终以失败告终。由于不熟悉NPM和Node.js,最后爆出的错误摸不到头脑,就此作罢。</p>\n<p>寻找另一个方法,在 <code>https://github.com/user/repo/actions/new</code> 中选择了跳过,自己设置一个空白的Workflow。</p>\n<ol>\n<li><p>为了避免Action重新推送仓库后循环触发Action(不知Github有没有对这种情况进行特殊处理)添加路径过滤器,仅当 <code>/source</code> 目录存在更新时才触发 Workflow</p>\n</li>\n<li><p>在仓库的 <code>Settings->Deploy keys</code> 里设置Github Action push时使用的SSH公钥,并赋予写权限,<code>Settings->Secrets</code> 里设置私钥的 Base64 编码。<br>私钥会通过环境变量传入Action的shell,<code>base64 -d</code> 即可解码,base64编码是为了避免潜在的回车换行符问题(环境变量里出现的换行符似乎不能正确地写入文件)</p>\n</li>\n<li><p>注意工作目录的问题,别瞎跑,目录会丢掉的</p>\n</li>\n<li><p><code>~/.ssh/id_rsa</code> 文件注意设定权限 <code>0600</code> 默认的权限过于宽松,SSH会不读取。</p>\n</li>\n<li><p><code>~/.ssh/config</code> 里需写入 </p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">Host *</span><br><span class=\"line\"> StrictHostKeyChecking no</span><br></pre></td></tr></table></figure>\n<p>否则可能会弹出要求确认SSH fingerprint的交互消息。</p>\n</li>\n<li><p>记得设定 <code>git config --global user.name/email</code> 否则无法提交</p>\n</li>\n<li><p>如果使用了自定义的域名,注意 <code>CNAME</code> 文件是否在 <code>hexo clean</code> 后被删除,可能需要自己写回去。</p>\n</li>\n<li><p>注意部分Hexo主题可能以 git submodule 方式引入, Github Action 克隆仓库时不会自动克隆子模块,导致生成的所有页面空白,Hexo只会给出警告而不是错误。</p>\n</li>\n</ol>\n<h3 id=\"附上自己写的workflow(糊成一坨,凑合能用)\"><a href=\"#附上自己写的workflow(糊成一坨,凑合能用)\" class=\"headerlink\" title=\"附上自己写的workflow(糊成一坨,凑合能用)\"></a>附上自己写的workflow(糊成一坨,凑合能用)</h3><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"attr\">name:</span> <span class=\"string\">Generate</span> <span class=\"string\">Hexo</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">on:</span></span><br><span class=\"line\"> <span class=\"attr\">push:</span> </span><br><span class=\"line\"> <span class=\"attr\">paths:</span> </span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"string\">'source/**'</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">jobs:</span> </span><br><span class=\"line\"> <span class=\"attr\">build:</span> </span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">Refresh</span></span><br><span class=\"line\"> <span class=\"attr\">runs-on:</span> <span class=\"string\">ubuntu-latest</span></span><br><span class=\"line\"> <span class=\"attr\">steps:</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Install</span> <span class=\"string\">Node.js</span> <span class=\"string\">and</span> <span class=\"string\">NPM</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> sudo apt-get install curl -y</span></span><br><span class=\"line\"><span class=\"string\"> curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -</span></span><br><span class=\"line\"><span class=\"string\"> sudo apt-get install nodejs -y</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show NPM version====='</span></span><br><span class=\"line\"><span class=\"string\"> npm -v</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show Node.js version====='</span></span><br><span class=\"line\"><span class=\"string\"> node -v</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Install</span> <span class=\"string\">Hexo</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> sudo npm install -g hexo-cli</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show HEXO version====='</span></span><br><span class=\"line\"><span class=\"string\"> hexo -v</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Prepare</span> <span class=\"string\">Key</span> <span class=\"string\">and</span> <span class=\"string\">SSH</span> <span class=\"string\">config</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> mkdir ~/.ssh</span></span><br><span class=\"line\"><span class=\"string\"> echo $DEPLOY_PRIVKEY | base64 -d > ~/.ssh/id_rsa</span></span><br><span class=\"line\"><span class=\"string\"> chmod 0600 ~/.ssh/id_rsa</span></span><br><span class=\"line\"><span class=\"string\"> echo 'Host *' >> ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"> echo ' StrictHostKeyChecking no' >> ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"> chmod 0600 ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"attr\">env:</span> </span><br><span class=\"line\"> <span class=\"attr\">DEPLOY_PRIVKEY:</span> <span class=\"string\">${{</span> <span class=\"string\">secrets.DEPLOY_PRIVKEY</span> <span class=\"string\">}}</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Clone</span> <span class=\"string\">git</span> <span class=\"string\">repo</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> cd ~</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show work path====='</span></span><br><span class=\"line\"><span class=\"string\"> pwd</span></span><br><span class=\"line\"><span class=\"string\"> git clone [email protected]:cpdyj/blog.git</span></span><br><span class=\"line\"><span class=\"string\"> cd blog</span></span><br><span class=\"line\"><span class=\"string\"> ls</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show work path====='</span></span><br><span class=\"line\"><span class=\"string\"> pwd</span></span><br><span class=\"line\"><span class=\"string\"> cat ./package.json</span></span><br><span class=\"line\"><span class=\"string\"> npm install</span></span><br><span class=\"line\"><span class=\"string\"> npm audit fix</span></span><br><span class=\"line\"><span class=\"string\"> hexo clean</span></span><br><span class=\"line\"><span class=\"string\"> hexo g</span></span><br><span class=\"line\"><span class=\"string\"> echo "blog.iseki.space" > ./docs/CNAME</span></span><br><span class=\"line\"><span class=\"string\"> git config --global user.name "User name"</span></span><br><span class=\"line\"><span class=\"string\"> git config --global user.email "[email protected]"</span></span><br><span class=\"line\"><span class=\"string\"> git add docs</span></span><br><span class=\"line\"><span class=\"string\"> git commit -am "Auto generate on Github Action at `date`"</span></span><br><span class=\"line\"><span class=\"string\"> git push</span></span><br></pre></td></tr></table></figure>\n","site":{"data":{}},"excerpt":"","more":"<p>不想阅读Github Action厚重的文档,用预配置好的NPM Action折腾了半天,终以失败告终。由于不熟悉NPM和Node.js,最后爆出的错误摸不到头脑,就此作罢。</p>\n<p>寻找另一个方法,在 <code>https://github.com/user/repo/actions/new</code> 中选择了跳过,自己设置一个空白的Workflow。</p>\n<ol>\n<li><p>为了避免Action重新推送仓库后循环触发Action(不知Github有没有对这种情况进行特殊处理)添加路径过滤器,仅当 <code>/source</code> 目录存在更新时才触发 Workflow</p>\n</li>\n<li><p>在仓库的 <code>Settings->Deploy keys</code> 里设置Github Action push时使用的SSH公钥,并赋予写权限,<code>Settings->Secrets</code> 里设置私钥的 Base64 编码。<br>私钥会通过环境变量传入Action的shell,<code>base64 -d</code> 即可解码,base64编码是为了避免潜在的回车换行符问题(环境变量里出现的换行符似乎不能正确地写入文件)</p>\n</li>\n<li><p>注意工作目录的问题,别瞎跑,目录会丢掉的</p>\n</li>\n<li><p><code>~/.ssh/id_rsa</code> 文件注意设定权限 <code>0600</code> 默认的权限过于宽松,SSH会不读取。</p>\n</li>\n<li><p><code>~/.ssh/config</code> 里需写入 </p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">Host *</span><br><span class=\"line\"> StrictHostKeyChecking no</span><br></pre></td></tr></table></figure>\n<p>否则可能会弹出要求确认SSH fingerprint的交互消息。</p>\n</li>\n<li><p>记得设定 <code>git config --global user.name/email</code> 否则无法提交</p>\n</li>\n<li><p>如果使用了自定义的域名,注意 <code>CNAME</code> 文件是否在 <code>hexo clean</code> 后被删除,可能需要自己写回去。</p>\n</li>\n<li><p>注意部分Hexo主题可能以 git submodule 方式引入, Github Action 克隆仓库时不会自动克隆子模块,导致生成的所有页面空白,Hexo只会给出警告而不是错误。</p>\n</li>\n</ol>\n<h3 id=\"附上自己写的workflow(糊成一坨,凑合能用)\"><a href=\"#附上自己写的workflow(糊成一坨,凑合能用)\" class=\"headerlink\" title=\"附上自己写的workflow(糊成一坨,凑合能用)\"></a>附上自己写的workflow(糊成一坨,凑合能用)</h3><figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"attr\">name:</span> <span class=\"string\">Generate</span> <span class=\"string\">Hexo</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">on:</span></span><br><span class=\"line\"> <span class=\"attr\">push:</span> </span><br><span class=\"line\"> <span class=\"attr\">paths:</span> </span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"string\">'source/**'</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">jobs:</span> </span><br><span class=\"line\"> <span class=\"attr\">build:</span> </span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">Refresh</span></span><br><span class=\"line\"> <span class=\"attr\">runs-on:</span> <span class=\"string\">ubuntu-latest</span></span><br><span class=\"line\"> <span class=\"attr\">steps:</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Install</span> <span class=\"string\">Node.js</span> <span class=\"string\">and</span> <span class=\"string\">NPM</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> sudo apt-get install curl -y</span></span><br><span class=\"line\"><span class=\"string\"> curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -</span></span><br><span class=\"line\"><span class=\"string\"> sudo apt-get install nodejs -y</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show NPM version====='</span></span><br><span class=\"line\"><span class=\"string\"> npm -v</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show Node.js version====='</span></span><br><span class=\"line\"><span class=\"string\"> node -v</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Install</span> <span class=\"string\">Hexo</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> sudo npm install -g hexo-cli</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show HEXO version====='</span></span><br><span class=\"line\"><span class=\"string\"> hexo -v</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Prepare</span> <span class=\"string\">Key</span> <span class=\"string\">and</span> <span class=\"string\">SSH</span> <span class=\"string\">config</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> mkdir ~/.ssh</span></span><br><span class=\"line\"><span class=\"string\"> echo $DEPLOY_PRIVKEY | base64 -d > ~/.ssh/id_rsa</span></span><br><span class=\"line\"><span class=\"string\"> chmod 0600 ~/.ssh/id_rsa</span></span><br><span class=\"line\"><span class=\"string\"> echo 'Host *' >> ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"> echo ' StrictHostKeyChecking no' >> ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"> chmod 0600 ~/.ssh/config</span></span><br><span class=\"line\"><span class=\"string\"></span> <span class=\"attr\">env:</span> </span><br><span class=\"line\"> <span class=\"attr\">DEPLOY_PRIVKEY:</span> <span class=\"string\">${{</span> <span class=\"string\">secrets.DEPLOY_PRIVKEY</span> <span class=\"string\">}}</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">Clone</span> <span class=\"string\">git</span> <span class=\"string\">repo</span></span><br><span class=\"line\"> <span class=\"attr\">run:</span> <span class=\"string\">|</span></span><br><span class=\"line\"><span class=\"string\"> cd ~</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show work path====='</span></span><br><span class=\"line\"><span class=\"string\"> pwd</span></span><br><span class=\"line\"><span class=\"string\"> git clone [email protected]:cpdyj/blog.git</span></span><br><span class=\"line\"><span class=\"string\"> cd blog</span></span><br><span class=\"line\"><span class=\"string\"> ls</span></span><br><span class=\"line\"><span class=\"string\"> echo '=====Show work path====='</span></span><br><span class=\"line\"><span class=\"string\"> pwd</span></span><br><span class=\"line\"><span class=\"string\"> cat ./package.json</span></span><br><span class=\"line\"><span class=\"string\"> npm install</span></span><br><span class=\"line\"><span class=\"string\"> npm audit fix</span></span><br><span class=\"line\"><span class=\"string\"> hexo clean</span></span><br><span class=\"line\"><span class=\"string\"> hexo g</span></span><br><span class=\"line\"><span class=\"string\"> echo "blog.iseki.space" > ./docs/CNAME</span></span><br><span class=\"line\"><span class=\"string\"> git config --global user.name "User name"</span></span><br><span class=\"line\"><span class=\"string\"> git config --global user.email "[email protected]"</span></span><br><span class=\"line\"><span class=\"string\"> git add docs</span></span><br><span class=\"line\"><span class=\"string\"> git commit -am "Auto generate on Github Action at `date`"</span></span><br><span class=\"line\"><span class=\"string\"> git push</span></span><br></pre></td></tr></table></figure>\n"},{"date":"2019-10-18T01:54:00.000Z","updated":"2019-10-18T01:54:00.000Z","title":"大佬们实在是太聚聚了,萌新咋活啊😐","_content":"感觉自己完了呢…\n","source":"_posts/dalao.md","raw":"---\ndate: 2019-10-18 9:54\nupdated: 2019-10-18 9:54\ntitle: 大佬们实在是太聚聚了,萌新咋活啊😐\ntags: [dalao]\n---\n感觉自己完了呢…\n","slug":"dalao","published":1,"_id":"clelf1dvg000no8uzdib5euvz","comments":1,"layout":"post","photos":[],"link":"","content":"<p>感觉自己完了呢…</p>\n","site":{"data":{}},"excerpt":"","more":"<p>感觉自己完了呢…</p>\n"},{"date":"2020-07-20T11:30:00.000Z","updated":"2020-07-20T11:30:00.000Z","title":"浅扯 Coroutine","_content":"# 浅扯 Coroutine\n\n关于 Kotlin Coroutine 的使用就不多说了,大家都已经很熟悉emmm,这里简单探索下 Coroutine 内部的实现,来尽量规避Coroutine 与其他库和框架协同使用时的坑。\n\n本文编写时使用 Kotlin 版本:`1.4-M3`,JDK 版本:`openjdk 11.0.7`\n\nCoroutine 的核心原理 [KEEP][KEEP] 中的 coroutine 提案已经写得很清楚了,详见提案的实现详情章节: [KEEP/proposals/coroutines.md#implementation-details](https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#implementation-details) ,这里补充一点点提案中没说的,和实现高度相关的内容。\n\n本质就是对 suspend 函数进行CPS变换,将代码转换为[延续体传递风格][Continuation-passing style]。简单来说就是为每个函数增加了一个隐式的参数 `$completion`,它的类型是 `Continuation` 即延续体;函数本体则被编译成状态机,状态存储于上述的 `Continuation` 中,suspend 函数每次 resume 时都会被调用,其根据 `Continuation` 中的状态信息直接调转到对应的位置继续执行。\n\n为了便于分析,这里使用 [CFR][CFR] 反编译器对 kotlinc 编译的 suspend 函数进行反编译,当前版本为 `0.150`\n\n我们从下面代码段开始:\n\n```kotlin\nclass Demo {\n suspend fun demo1(s: String) {\n println(\"1==========\")\n delay(100)\n println(\"2==========\")\n }\n}\n```\n\n注意,Kotlin 编译器对其进行编译后我们看到两个 class `Demo$demo1$1.class` `Demo.class` 前面那个是后面的匿名内部类,不用管它,用 cfr 反编译后面的就行了。以下我将只节选部分源码,注意这不是标准的Java代码,没法直接编译\n\n```java\npublic final class Demo {\n /*\n * Unable to fully structure code\n * Enabled aggressive block sorting\n * Lifted jumps to return sites\n */\n @Nullable\n public final Object demo1(@NotNull String s, @NotNull Continuation<? super Unit> $completion) {\n if (!($completion instanceof demo1.1)) ** GOTO lbl-1000\n // 这个 demo1.1 就是下面new出来的那个ContinuationImpl\n var6_3 = $completion;\n if ((var6_3.label & -2147483648) != 0) {\n var6_3.label -= -2147483648;\n } else lbl-1000:\n // 2 sources\n\n {\n $continuation = new ContinuationImpl(this, $completion){\n /* synthetic */ Object result;\n int label;\n final /* synthetic */ Demo this$0;\n Object L$0;\n Object L$1;\n\n @Nullable\n public final Object invokeSuspend(@NotNull Object $result) {\n this.result = $result;\n this.label |= Integer.MIN_VALUE;\n return this.this$0.demo1(null, (Continuation<? super Unit>)this);\n }\n {\n this.this$0 = demo;\n super(continuation);\n }\n };\n }\n $result = $continuation.result;\n var7_5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();\n switch ($continuation.label) {\n case 0: {\n ResultKt.throwOnFailure((Object)$result);\n var3_6 = \"1==========\";\n var4_7 = false;\n System.out.println((Object)var3_6);\n $continuation.L$0 = this;\n $continuation.L$1 = s;\n $continuation.label = 1;\n v0 = DelayKt.delay((long)100L, (Continuation)$continuation);\n if (v0 == var7_5) { // if result == COROUTINE_SUSPENDED\n return var7_5; // return COROUTINE_SUSPEND\n }\n ** GOTO lbl27 // else goto lbl27\n }\n case 1: {\n // 状态机在这里 resume,先恢复局部变量\n s = (String)$continuation.L$1;\n this = (Demo)$continuation.L$0;\n ResultKt.throwOnFailure((Object)$result);\n v0 = $result;\nlbl27:\n // 2 sources\n // 如果一开始就没有挂起,那自然也就不需要恢复咯\n var3_6 = \"2==========\";\n var4_7 = false;\n System.out.println((Object)var3_6);\n return Unit.INSTANCE;\n }\n }\n throw new IllegalStateException(\"call to 'resume' before 'invoke' with coroutine\");\n }\n}\n```\n\n上面这个很清晰了,这个 suspend 真正被调用时会创建一个 ContinuationImpl 的子类,里边存放了状态机的状态 `label` 和局部变量,还有最关键的,传进来的调用者的延续体也被包含在了里面,这个稍后会用到。\n\n当协程挂起时,状态机函数会返回 `COROUTINE_SUSPEND` 这个对象,这也就是 suspend 函数编译后函数返回值必然为 Any 的原因,实际的返回值是 返回值 T 和 COROUTINE_SUSPEND 之一,显然这是在 Java 和 Kotlin 类型系统中均无法表达的。局部变量等状态信息,都会在调用下一个 suspend 函数前保存进延续体 (45~47) \n\n 接下来看一看 CoroutineImpl 这个类到底干了什么,这个类的代码很多,我不全粘过来了,只节选有意义的部分\n\n```kotlin\npublic final override fun resumeWith(result: Result<Any?>) {\n // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume\n var current = this\n var param = result\n while (true) {\n // Invoke \"resume\" debug probe on every resumed continuation, so that a debugging library infrastructure\n // can precisely track what part of suspended callstack was already resumed\n probeCoroutineResumed(current)\n with(current) {\n val completion = completion!! // fail fast when trying to resume continuation without completion\n val outcome: Result<Any?> =\n try {\n val outcome = invokeSuspend(param)\n if (outcome === COROUTINE_SUSPENDED) return\n Result.success(outcome)\n } catch (exception: Throwable) {\n Result.failure(exception)\n }\n releaseIntercepted() // this state machine instance is terminating\n if (completion is BaseContinuationImpl) {\n // unrolling recursion via loop\n current = completion\n param = outcome\n } else {\n // top-level completion reached -- invoke and return\n completion.resumeWith(outcome)\n return\n }\n }\n }\n }\n```\n\n其实这个函数做的事很简单,不停的循环并调用 current 指针的 invokeSuspend 函数来恢复协程的执行,如果返回 COROUTINE_SUSPEND 那就意味着又是暂停,返回;否则说明当前函数执行完了,从 current 指针指向的延续体中拿出它上一级的延续体,继续 invoke,直到回到根,结束退出。\n\n总结下,传入每个 suspend 函数的延续体在初始时都是调用者的延续体,当 resume 时会传入本函数的延续体,并根据里边的 label 去往相应的状态,同时协程暂停时会返回那个特殊的 COROUTINE_SUSPEND 对象。\n\n\n\n\n\n[Continuation-passing style]: https://en.wikipedia.org/wiki/Continuation-passing_style \"[CPS] 延续体传递风格(WikiPedia[英文])\"\n\n[KEEP]: https://github.com/Kotlin/KEEP \"Kotlin Evolution and Enhancement Process\"\n\n[CFR]: https://www.benf.org/other/cfr/ \"CFR - another java decompiler\"","source":"_posts/some-of-coroutine-suspend-function.md","raw":"---\ndate: 2020-07-20 19:30:00\nupdated: 2020-07-20 19:30:00\ntitle: 浅扯 Coroutine\ntags: [kotlin, coroutine]\n---\n# 浅扯 Coroutine\n\n关于 Kotlin Coroutine 的使用就不多说了,大家都已经很熟悉emmm,这里简单探索下 Coroutine 内部的实现,来尽量规避Coroutine 与其他库和框架协同使用时的坑。\n\n本文编写时使用 Kotlin 版本:`1.4-M3`,JDK 版本:`openjdk 11.0.7`\n\nCoroutine 的核心原理 [KEEP][KEEP] 中的 coroutine 提案已经写得很清楚了,详见提案的实现详情章节: [KEEP/proposals/coroutines.md#implementation-details](https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#implementation-details) ,这里补充一点点提案中没说的,和实现高度相关的内容。\n\n本质就是对 suspend 函数进行CPS变换,将代码转换为[延续体传递风格][Continuation-passing style]。简单来说就是为每个函数增加了一个隐式的参数 `$completion`,它的类型是 `Continuation` 即延续体;函数本体则被编译成状态机,状态存储于上述的 `Continuation` 中,suspend 函数每次 resume 时都会被调用,其根据 `Continuation` 中的状态信息直接调转到对应的位置继续执行。\n\n为了便于分析,这里使用 [CFR][CFR] 反编译器对 kotlinc 编译的 suspend 函数进行反编译,当前版本为 `0.150`\n\n我们从下面代码段开始:\n\n```kotlin\nclass Demo {\n suspend fun demo1(s: String) {\n println(\"1==========\")\n delay(100)\n println(\"2==========\")\n }\n}\n```\n\n注意,Kotlin 编译器对其进行编译后我们看到两个 class `Demo$demo1$1.class` `Demo.class` 前面那个是后面的匿名内部类,不用管它,用 cfr 反编译后面的就行了。以下我将只节选部分源码,注意这不是标准的Java代码,没法直接编译\n\n```java\npublic final class Demo {\n /*\n * Unable to fully structure code\n * Enabled aggressive block sorting\n * Lifted jumps to return sites\n */\n @Nullable\n public final Object demo1(@NotNull String s, @NotNull Continuation<? super Unit> $completion) {\n if (!($completion instanceof demo1.1)) ** GOTO lbl-1000\n // 这个 demo1.1 就是下面new出来的那个ContinuationImpl\n var6_3 = $completion;\n if ((var6_3.label & -2147483648) != 0) {\n var6_3.label -= -2147483648;\n } else lbl-1000:\n // 2 sources\n\n {\n $continuation = new ContinuationImpl(this, $completion){\n /* synthetic */ Object result;\n int label;\n final /* synthetic */ Demo this$0;\n Object L$0;\n Object L$1;\n\n @Nullable\n public final Object invokeSuspend(@NotNull Object $result) {\n this.result = $result;\n this.label |= Integer.MIN_VALUE;\n return this.this$0.demo1(null, (Continuation<? super Unit>)this);\n }\n {\n this.this$0 = demo;\n super(continuation);\n }\n };\n }\n $result = $continuation.result;\n var7_5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();\n switch ($continuation.label) {\n case 0: {\n ResultKt.throwOnFailure((Object)$result);\n var3_6 = \"1==========\";\n var4_7 = false;\n System.out.println((Object)var3_6);\n $continuation.L$0 = this;\n $continuation.L$1 = s;\n $continuation.label = 1;\n v0 = DelayKt.delay((long)100L, (Continuation)$continuation);\n if (v0 == var7_5) { // if result == COROUTINE_SUSPENDED\n return var7_5; // return COROUTINE_SUSPEND\n }\n ** GOTO lbl27 // else goto lbl27\n }\n case 1: {\n // 状态机在这里 resume,先恢复局部变量\n s = (String)$continuation.L$1;\n this = (Demo)$continuation.L$0;\n ResultKt.throwOnFailure((Object)$result);\n v0 = $result;\nlbl27:\n // 2 sources\n // 如果一开始就没有挂起,那自然也就不需要恢复咯\n var3_6 = \"2==========\";\n var4_7 = false;\n System.out.println((Object)var3_6);\n return Unit.INSTANCE;\n }\n }\n throw new IllegalStateException(\"call to 'resume' before 'invoke' with coroutine\");\n }\n}\n```\n\n上面这个很清晰了,这个 suspend 真正被调用时会创建一个 ContinuationImpl 的子类,里边存放了状态机的状态 `label` 和局部变量,还有最关键的,传进来的调用者的延续体也被包含在了里面,这个稍后会用到。\n\n当协程挂起时,状态机函数会返回 `COROUTINE_SUSPEND` 这个对象,这也就是 suspend 函数编译后函数返回值必然为 Any 的原因,实际的返回值是 返回值 T 和 COROUTINE_SUSPEND 之一,显然这是在 Java 和 Kotlin 类型系统中均无法表达的。局部变量等状态信息,都会在调用下一个 suspend 函数前保存进延续体 (45~47) \n\n 接下来看一看 CoroutineImpl 这个类到底干了什么,这个类的代码很多,我不全粘过来了,只节选有意义的部分\n\n```kotlin\npublic final override fun resumeWith(result: Result<Any?>) {\n // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume\n var current = this\n var param = result\n while (true) {\n // Invoke \"resume\" debug probe on every resumed continuation, so that a debugging library infrastructure\n // can precisely track what part of suspended callstack was already resumed\n probeCoroutineResumed(current)\n with(current) {\n val completion = completion!! // fail fast when trying to resume continuation without completion\n val outcome: Result<Any?> =\n try {\n val outcome = invokeSuspend(param)\n if (outcome === COROUTINE_SUSPENDED) return\n Result.success(outcome)\n } catch (exception: Throwable) {\n Result.failure(exception)\n }\n releaseIntercepted() // this state machine instance is terminating\n if (completion is BaseContinuationImpl) {\n // unrolling recursion via loop\n current = completion\n param = outcome\n } else {\n // top-level completion reached -- invoke and return\n completion.resumeWith(outcome)\n return\n }\n }\n }\n }\n```\n\n其实这个函数做的事很简单,不停的循环并调用 current 指针的 invokeSuspend 函数来恢复协程的执行,如果返回 COROUTINE_SUSPEND 那就意味着又是暂停,返回;否则说明当前函数执行完了,从 current 指针指向的延续体中拿出它上一级的延续体,继续 invoke,直到回到根,结束退出。\n\n总结下,传入每个 suspend 函数的延续体在初始时都是调用者的延续体,当 resume 时会传入本函数的延续体,并根据里边的 label 去往相应的状态,同时协程暂停时会返回那个特殊的 COROUTINE_SUSPEND 对象。\n\n\n\n\n\n[Continuation-passing style]: https://en.wikipedia.org/wiki/Continuation-passing_style \"[CPS] 延续体传递风格(WikiPedia[英文])\"\n\n[KEEP]: https://github.com/Kotlin/KEEP \"Kotlin Evolution and Enhancement Process\"\n\n[CFR]: https://www.benf.org/other/cfr/ \"CFR - another java decompiler\"","slug":"some-of-coroutine-suspend-function","published":1,"_id":"clelf1dw2000qo8uzbynx1i62","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"浅扯-Coroutine\"><a href=\"#浅扯-Coroutine\" class=\"headerlink\" title=\"浅扯 Coroutine\"></a>浅扯 Coroutine</h1><p>关于 Kotlin Coroutine 的使用就不多说了,大家都已经很熟悉emmm,这里简单探索下 Coroutine 内部的实现,来尽量规避Coroutine 与其他库和框架协同使用时的坑。</p>\n<p>本文编写时使用 Kotlin 版本:<code>1.4-M3</code>,JDK 版本:<code>openjdk 11.0.7</code></p>\n<p>Coroutine 的核心原理 <a href=\"https://github.com/Kotlin/KEEP\" title=\"Kotlin Evolution and Enhancement Process\">KEEP</a> 中的 coroutine 提案已经写得很清楚了,详见提案的实现详情章节: <a href=\"https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#implementation-details\">KEEP/proposals/coroutines.md#implementation-details</a> ,这里补充一点点提案中没说的,和实现高度相关的内容。</p>\n<p>本质就是对 suspend 函数进行CPS变换,将代码转换为<a href=\"https://en.wikipedia.org/wiki/Continuation-passing_style\" title=\"[CPS] 延续体传递风格(WikiPedia[英文])\">延续体传递风格</a>。简单来说就是为每个函数增加了一个隐式的参数 <code>$completion</code>,它的类型是 <code>Continuation</code> 即延续体;函数本体则被编译成状态机,状态存储于上述的 <code>Continuation</code> 中,suspend 函数每次 resume 时都会被调用,其根据 <code>Continuation</code> 中的状态信息直接调转到对应的位置继续执行。</p>\n<p>为了便于分析,这里使用 <a href=\"https://www.benf.org/other/cfr/\" title=\"CFR - another java decompiler\">CFR</a> 反编译器对 kotlinc 编译的 suspend 函数进行反编译,当前版本为 <code>0.150</code></p>\n<p>我们从下面代码段开始:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">class</span> <span class=\"title class_\">Demo</span> {</span><br><span class=\"line\"> <span class=\"keyword\">suspend</span> <span class=\"function\"><span class=\"keyword\">fun</span> <span class=\"title\">demo1</span><span class=\"params\">(s: <span class=\"type\">String</span>)</span></span> {</span><br><span class=\"line\"> println(<span class=\"string\">"1=========="</span>)</span><br><span class=\"line\"> delay(<span class=\"number\">100</span>)</span><br><span class=\"line\"> println(<span class=\"string\">"2=========="</span>)</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>注意,Kotlin 编译器对其进行编译后我们看到两个 class <code>Demo$demo1$1.class</code> <code>Demo.class</code> 前面那个是后面的匿名内部类,不用管它,用 cfr 反编译后面的就行了。以下我将只节选部分源码,注意这不是标准的Java代码,没法直接编译</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">final</span> <span class=\"keyword\">class</span> <span class=\"title class_\">Demo</span> {</span><br><span class=\"line\"> <span class=\"comment\">/*</span></span><br><span class=\"line\"><span class=\"comment\"> * Unable to fully structure code</span></span><br><span class=\"line\"><span class=\"comment\"> * Enabled aggressive block sorting</span></span><br><span class=\"line\"><span class=\"comment\"> * Lifted jumps to return sites</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Nullable</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">final</span> Object <span class=\"title function_\">demo1</span><span class=\"params\">(<span class=\"meta\">@NotNull</span> String s, <span class=\"meta\">@NotNull</span> Continuation<? <span class=\"built_in\">super</span> Unit> $completion)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!($completion <span class=\"keyword\">instanceof</span> demo1<span class=\"number\">.1</span>)) ** GOTO lbl-<span class=\"number\">1000</span></span><br><span class=\"line\"> <span class=\"comment\">// 这个 demo1.1 就是下面new出来的那个ContinuationImpl</span></span><br><span class=\"line\"> var6_3 = $completion;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> ((var6_3.label & -<span class=\"number\">2147483648</span>) != <span class=\"number\">0</span>) {</span><br><span class=\"line\"> var6_3.label -= -<span class=\"number\">2147483648</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> lbl-<span class=\"number\">1000</span>:</span><br><span class=\"line\"> <span class=\"comment\">// 2 sources</span></span><br><span class=\"line\"></span><br><span class=\"line\"> {</span><br><span class=\"line\"> $continuation = <span class=\"keyword\">new</span> <span class=\"title class_\">ContinuationImpl</span>(<span class=\"built_in\">this</span>, $completion){</span><br><span class=\"line\"> <span class=\"comment\">/* synthetic */</span> Object result;</span><br><span class=\"line\"> <span class=\"type\">int</span> label;</span><br><span class=\"line\"> <span class=\"keyword\">final</span> <span class=\"comment\">/* synthetic */</span> Demo <span class=\"built_in\">this</span>$<span class=\"number\">0</span>;</span><br><span class=\"line\"> Object L$<span class=\"number\">0</span>;</span><br><span class=\"line\"> Object L$<span class=\"number\">1</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Nullable</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">final</span> Object <span class=\"title function_\">invokeSuspend</span><span class=\"params\">(<span class=\"meta\">@NotNull</span> Object $result)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.result = $result;</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.label |= Integer.MIN_VALUE;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">this</span>.<span class=\"built_in\">this</span>$<span class=\"number\">0.</span>demo1(<span class=\"literal\">null</span>, (Continuation<? <span class=\"built_in\">super</span> Unit>)<span class=\"built_in\">this</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.<span class=\"built_in\">this</span>$<span class=\"number\">0</span> = demo;</span><br><span class=\"line\"> <span class=\"built_in\">super</span>(continuation);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> };</span><br><span class=\"line\"> }</span><br><span class=\"line\"> $result = $continuation.result;</span><br><span class=\"line\"> var7_5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();</span><br><span class=\"line\"> <span class=\"keyword\">switch</span> ($continuation.label) {</span><br><span class=\"line\"> <span class=\"keyword\">case</span> <span class=\"number\">0</span>: {</span><br><span class=\"line\"> ResultKt.throwOnFailure((Object)$result);</span><br><span class=\"line\"> var3_6 = <span class=\"string\">"1=========="</span>;</span><br><span class=\"line\"> var4_7 = <span class=\"literal\">false</span>;</span><br><span class=\"line\"> System.out.println((Object)var3_6);</span><br><span class=\"line\"> $continuation.L$<span class=\"number\">0</span> = <span class=\"built_in\">this</span>;</span><br><span class=\"line\"> $continuation.L$<span class=\"number\">1</span> = s;</span><br><span class=\"line\"> $continuation.label = <span class=\"number\">1</span>;</span><br><span class=\"line\"> v0 = DelayKt.delay((<span class=\"type\">long</span>)<span class=\"number\">100L</span>, (Continuation)$continuation);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (v0 == var7_5) { <span class=\"comment\">// if result == COROUTINE_SUSPENDED</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> var7_5; <span class=\"comment\">// return COROUTINE_SUSPEND</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> ** GOTO lbl27 <span class=\"comment\">// else goto lbl27</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">case</span> <span class=\"number\">1</span>: {</span><br><span class=\"line\"> <span class=\"comment\">// 状态机在这里 resume,先恢复局部变量</span></span><br><span class=\"line\"> s = (String)$continuation.L$<span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"built_in\">this</span> = (Demo)$continuation.L$<span class=\"number\">0</span>;</span><br><span class=\"line\"> ResultKt.throwOnFailure((Object)$result);</span><br><span class=\"line\"> v0 = $result;</span><br><span class=\"line\">lbl27:</span><br><span class=\"line\"> <span class=\"comment\">// 2 sources</span></span><br><span class=\"line\"> <span class=\"comment\">// 如果一开始就没有挂起,那自然也就不需要恢复咯</span></span><br><span class=\"line\"> var3_6 = <span class=\"string\">"2=========="</span>;</span><br><span class=\"line\"> var4_7 = <span class=\"literal\">false</span>;</span><br><span class=\"line\"> System.out.println((Object)var3_6);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> Unit.INSTANCE;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> <span class=\"title class_\">IllegalStateException</span>(<span class=\"string\">"call to 'resume' before 'invoke' with coroutine"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>上面这个很清晰了,这个 suspend 真正被调用时会创建一个 ContinuationImpl 的子类,里边存放了状态机的状态 <code>label</code> 和局部变量,还有最关键的,传进来的调用者的延续体也被包含在了里面,这个稍后会用到。</p>\n<p>当协程挂起时,状态机函数会返回 <code>COROUTINE_SUSPEND</code> 这个对象,这也就是 suspend 函数编译后函数返回值必然为 Any 的原因,实际的返回值是 返回值 T 和 COROUTINE_SUSPEND 之一,显然这是在 Java 和 Kotlin 类型系统中均无法表达的。局部变量等状态信息,都会在调用下一个 suspend 函数前保存进延续体 (45~47) </p>\n<p> 接下来看一看 CoroutineImpl 这个类到底干了什么,这个类的代码很多,我不全粘过来了,只节选有意义的部分</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">final</span> <span class=\"keyword\">override</span> <span class=\"function\"><span class=\"keyword\">fun</span> <span class=\"title\">resumeWith</span><span class=\"params\">(result: <span class=\"type\">Result</span><<span class=\"type\">Any</span>?>)</span></span> {</span><br><span class=\"line\"> <span class=\"comment\">// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume</span></span><br><span class=\"line\"> <span class=\"keyword\">var</span> current = <span class=\"keyword\">this</span></span><br><span class=\"line\"> <span class=\"keyword\">var</span> param = result</span><br><span class=\"line\"> <span class=\"keyword\">while</span> (<span class=\"literal\">true</span>) {</span><br><span class=\"line\"> <span class=\"comment\">// Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure</span></span><br><span class=\"line\"> <span class=\"comment\">// can precisely track what part of suspended callstack was already resumed</span></span><br><span class=\"line\"> probeCoroutineResumed(current)</span><br><span class=\"line\"> with(current) {</span><br><span class=\"line\"> <span class=\"keyword\">val</span> completion = completion!! <span class=\"comment\">// fail fast when trying to resume continuation without completion</span></span><br><span class=\"line\"> <span class=\"keyword\">val</span> outcome: Result<Any?> =</span><br><span class=\"line\"> <span class=\"keyword\">try</span> {</span><br><span class=\"line\"> <span class=\"keyword\">val</span> outcome = invokeSuspend(param)</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (outcome === COROUTINE_SUSPENDED) <span class=\"keyword\">return</span></span><br><span class=\"line\"> Result.success(outcome)</span><br><span class=\"line\"> } <span class=\"keyword\">catch</span> (exception: Throwable) {</span><br><span class=\"line\"> Result.failure(exception)</span><br><span class=\"line\"> }</span><br><span class=\"line\"> releaseIntercepted() <span class=\"comment\">// this state machine instance is terminating</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (completion <span class=\"keyword\">is</span> BaseContinuationImpl) {</span><br><span class=\"line\"> <span class=\"comment\">// unrolling recursion via loop</span></span><br><span class=\"line\"> current = completion</span><br><span class=\"line\"> param = outcome</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">// top-level completion reached -- invoke and return</span></span><br><span class=\"line\"> completion.resumeWith(outcome)</span><br><span class=\"line\"> <span class=\"keyword\">return</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n\n<p>其实这个函数做的事很简单,不停的循环并调用 current 指针的 invokeSuspend 函数来恢复协程的执行,如果返回 COROUTINE_SUSPEND 那就意味着又是暂停,返回;否则说明当前函数执行完了,从 current 指针指向的延续体中拿出它上一级的延续体,继续 invoke,直到回到根,结束退出。</p>\n<p>总结下,传入每个 suspend 函数的延续体在初始时都是调用者的延续体,当 resume 时会传入本函数的延续体,并根据里边的 label 去往相应的状态,同时协程暂停时会返回那个特殊的 COROUTINE_SUSPEND 对象。</p>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"浅扯-Coroutine\"><a href=\"#浅扯-Coroutine\" class=\"headerlink\" title=\"浅扯 Coroutine\"></a>浅扯 Coroutine</h1><p>关于 Kotlin Coroutine 的使用就不多说了,大家都已经很熟悉emmm,这里简单探索下 Coroutine 内部的实现,来尽量规避Coroutine 与其他库和框架协同使用时的坑。</p>\n<p>本文编写时使用 Kotlin 版本:<code>1.4-M3</code>,JDK 版本:<code>openjdk 11.0.7</code></p>\n<p>Coroutine 的核心原理 <a href=\"https://github.com/Kotlin/KEEP\" title=\"Kotlin Evolution and Enhancement Process\">KEEP</a> 中的 coroutine 提案已经写得很清楚了,详见提案的实现详情章节: <a href=\"https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#implementation-details\">KEEP/proposals/coroutines.md#implementation-details</a> ,这里补充一点点提案中没说的,和实现高度相关的内容。</p>\n<p>本质就是对 suspend 函数进行CPS变换,将代码转换为<a href=\"https://en.wikipedia.org/wiki/Continuation-passing_style\" title=\"[CPS] 延续体传递风格(WikiPedia[英文])\">延续体传递风格</a>。简单来说就是为每个函数增加了一个隐式的参数 <code>$completion</code>,它的类型是 <code>Continuation</code> 即延续体;函数本体则被编译成状态机,状态存储于上述的 <code>Continuation</code> 中,suspend 函数每次 resume 时都会被调用,其根据 <code>Continuation</code> 中的状态信息直接调转到对应的位置继续执行。</p>\n<p>为了便于分析,这里使用 <a href=\"https://www.benf.org/other/cfr/\" title=\"CFR - another java decompiler\">CFR</a> 反编译器对 kotlinc 编译的 suspend 函数进行反编译,当前版本为 <code>0.150</code></p>\n<p>我们从下面代码段开始:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">class</span> <span class=\"title class_\">Demo</span> {</span><br><span class=\"line\"> <span class=\"keyword\">suspend</span> <span class=\"function\"><span class=\"keyword\">fun</span> <span class=\"title\">demo1</span><span class=\"params\">(s: <span class=\"type\">String</span>)</span></span> {</span><br><span class=\"line\"> println(<span class=\"string\">"1=========="</span>)</span><br><span class=\"line\"> delay(<span class=\"number\">100</span>)</span><br><span class=\"line\"> println(<span class=\"string\">"2=========="</span>)</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>注意,Kotlin 编译器对其进行编译后我们看到两个 class <code>Demo$demo1$1.class</code> <code>Demo.class</code> 前面那个是后面的匿名内部类,不用管它,用 cfr 反编译后面的就行了。以下我将只节选部分源码,注意这不是标准的Java代码,没法直接编译</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">final</span> <span class=\"keyword\">class</span> <span class=\"title class_\">Demo</span> {</span><br><span class=\"line\"> <span class=\"comment\">/*</span></span><br><span class=\"line\"><span class=\"comment\"> * Unable to fully structure code</span></span><br><span class=\"line\"><span class=\"comment\"> * Enabled aggressive block sorting</span></span><br><span class=\"line\"><span class=\"comment\"> * Lifted jumps to return sites</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Nullable</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">final</span> Object <span class=\"title function_\">demo1</span><span class=\"params\">(<span class=\"meta\">@NotNull</span> String s, <span class=\"meta\">@NotNull</span> Continuation<? <span class=\"built_in\">super</span> Unit> $completion)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!($completion <span class=\"keyword\">instanceof</span> demo1<span class=\"number\">.1</span>)) ** GOTO lbl-<span class=\"number\">1000</span></span><br><span class=\"line\"> <span class=\"comment\">// 这个 demo1.1 就是下面new出来的那个ContinuationImpl</span></span><br><span class=\"line\"> var6_3 = $completion;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> ((var6_3.label & -<span class=\"number\">2147483648</span>) != <span class=\"number\">0</span>) {</span><br><span class=\"line\"> var6_3.label -= -<span class=\"number\">2147483648</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> lbl-<span class=\"number\">1000</span>:</span><br><span class=\"line\"> <span class=\"comment\">// 2 sources</span></span><br><span class=\"line\"></span><br><span class=\"line\"> {</span><br><span class=\"line\"> $continuation = <span class=\"keyword\">new</span> <span class=\"title class_\">ContinuationImpl</span>(<span class=\"built_in\">this</span>, $completion){</span><br><span class=\"line\"> <span class=\"comment\">/* synthetic */</span> Object result;</span><br><span class=\"line\"> <span class=\"type\">int</span> label;</span><br><span class=\"line\"> <span class=\"keyword\">final</span> <span class=\"comment\">/* synthetic */</span> Demo <span class=\"built_in\">this</span>$<span class=\"number\">0</span>;</span><br><span class=\"line\"> Object L$<span class=\"number\">0</span>;</span><br><span class=\"line\"> Object L$<span class=\"number\">1</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Nullable</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">final</span> Object <span class=\"title function_\">invokeSuspend</span><span class=\"params\">(<span class=\"meta\">@NotNull</span> Object $result)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.result = $result;</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.label |= Integer.MIN_VALUE;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">this</span>.<span class=\"built_in\">this</span>$<span class=\"number\">0.</span>demo1(<span class=\"literal\">null</span>, (Continuation<? <span class=\"built_in\">super</span> Unit>)<span class=\"built_in\">this</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.<span class=\"built_in\">this</span>$<span class=\"number\">0</span> = demo;</span><br><span class=\"line\"> <span class=\"built_in\">super</span>(continuation);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> };</span><br><span class=\"line\"> }</span><br><span class=\"line\"> $result = $continuation.result;</span><br><span class=\"line\"> var7_5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();</span><br><span class=\"line\"> <span class=\"keyword\">switch</span> ($continuation.label) {</span><br><span class=\"line\"> <span class=\"keyword\">case</span> <span class=\"number\">0</span>: {</span><br><span class=\"line\"> ResultKt.throwOnFailure((Object)$result);</span><br><span class=\"line\"> var3_6 = <span class=\"string\">"1=========="</span>;</span><br><span class=\"line\"> var4_7 = <span class=\"literal\">false</span>;</span><br><span class=\"line\"> System.out.println((Object)var3_6);</span><br><span class=\"line\"> $continuation.L$<span class=\"number\">0</span> = <span class=\"built_in\">this</span>;</span><br><span class=\"line\"> $continuation.L$<span class=\"number\">1</span> = s;</span><br><span class=\"line\"> $continuation.label = <span class=\"number\">1</span>;</span><br><span class=\"line\"> v0 = DelayKt.delay((<span class=\"type\">long</span>)<span class=\"number\">100L</span>, (Continuation)$continuation);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (v0 == var7_5) { <span class=\"comment\">// if result == COROUTINE_SUSPENDED</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> var7_5; <span class=\"comment\">// return COROUTINE_SUSPEND</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> ** GOTO lbl27 <span class=\"comment\">// else goto lbl27</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">case</span> <span class=\"number\">1</span>: {</span><br><span class=\"line\"> <span class=\"comment\">// 状态机在这里 resume,先恢复局部变量</span></span><br><span class=\"line\"> s = (String)$continuation.L$<span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"built_in\">this</span> = (Demo)$continuation.L$<span class=\"number\">0</span>;</span><br><span class=\"line\"> ResultKt.throwOnFailure((Object)$result);</span><br><span class=\"line\"> v0 = $result;</span><br><span class=\"line\">lbl27:</span><br><span class=\"line\"> <span class=\"comment\">// 2 sources</span></span><br><span class=\"line\"> <span class=\"comment\">// 如果一开始就没有挂起,那自然也就不需要恢复咯</span></span><br><span class=\"line\"> var3_6 = <span class=\"string\">"2=========="</span>;</span><br><span class=\"line\"> var4_7 = <span class=\"literal\">false</span>;</span><br><span class=\"line\"> System.out.println((Object)var3_6);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> Unit.INSTANCE;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> <span class=\"title class_\">IllegalStateException</span>(<span class=\"string\">"call to 'resume' before 'invoke' with coroutine"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>上面这个很清晰了,这个 suspend 真正被调用时会创建一个 ContinuationImpl 的子类,里边存放了状态机的状态 <code>label</code> 和局部变量,还有最关键的,传进来的调用者的延续体也被包含在了里面,这个稍后会用到。</p>\n<p>当协程挂起时,状态机函数会返回 <code>COROUTINE_SUSPEND</code> 这个对象,这也就是 suspend 函数编译后函数返回值必然为 Any 的原因,实际的返回值是 返回值 T 和 COROUTINE_SUSPEND 之一,显然这是在 Java 和 Kotlin 类型系统中均无法表达的。局部变量等状态信息,都会在调用下一个 suspend 函数前保存进延续体 (45~47) </p>\n<p> 接下来看一看 CoroutineImpl 这个类到底干了什么,这个类的代码很多,我不全粘过来了,只节选有意义的部分</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">final</span> <span class=\"keyword\">override</span> <span class=\"function\"><span class=\"keyword\">fun</span> <span class=\"title\">resumeWith</span><span class=\"params\">(result: <span class=\"type\">Result</span><<span class=\"type\">Any</span>?>)</span></span> {</span><br><span class=\"line\"> <span class=\"comment\">// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume</span></span><br><span class=\"line\"> <span class=\"keyword\">var</span> current = <span class=\"keyword\">this</span></span><br><span class=\"line\"> <span class=\"keyword\">var</span> param = result</span><br><span class=\"line\"> <span class=\"keyword\">while</span> (<span class=\"literal\">true</span>) {</span><br><span class=\"line\"> <span class=\"comment\">// Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure</span></span><br><span class=\"line\"> <span class=\"comment\">// can precisely track what part of suspended callstack was already resumed</span></span><br><span class=\"line\"> probeCoroutineResumed(current)</span><br><span class=\"line\"> with(current) {</span><br><span class=\"line\"> <span class=\"keyword\">val</span> completion = completion!! <span class=\"comment\">// fail fast when trying to resume continuation without completion</span></span><br><span class=\"line\"> <span class=\"keyword\">val</span> outcome: Result<Any?> =</span><br><span class=\"line\"> <span class=\"keyword\">try</span> {</span><br><span class=\"line\"> <span class=\"keyword\">val</span> outcome = invokeSuspend(param)</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (outcome === COROUTINE_SUSPENDED) <span class=\"keyword\">return</span></span><br><span class=\"line\"> Result.success(outcome)</span><br><span class=\"line\"> } <span class=\"keyword\">catch</span> (exception: Throwable) {</span><br><span class=\"line\"> Result.failure(exception)</span><br><span class=\"line\"> }</span><br><span class=\"line\"> releaseIntercepted() <span class=\"comment\">// this state machine instance is terminating</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (completion <span class=\"keyword\">is</span> BaseContinuationImpl) {</span><br><span class=\"line\"> <span class=\"comment\">// unrolling recursion via loop</span></span><br><span class=\"line\"> current = completion</span><br><span class=\"line\"> param = outcome</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">// top-level completion reached -- invoke and return</span></span><br><span class=\"line\"> completion.resumeWith(outcome)</span><br><span class=\"line\"> <span class=\"keyword\">return</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n\n<p>其实这个函数做的事很简单,不停的循环并调用 current 指针的 invokeSuspend 函数来恢复协程的执行,如果返回 COROUTINE_SUSPEND 那就意味着又是暂停,返回;否则说明当前函数执行完了,从 current 指针指向的延续体中拿出它上一级的延续体,继续 invoke,直到回到根,结束退出。</p>\n<p>总结下,传入每个 suspend 函数的延续体在初始时都是调用者的延续体,当 resume 时会传入本函数的延续体,并根据里边的 label 去往相应的状态,同时协程暂停时会返回那个特殊的 COROUTINE_SUSPEND 对象。</p>\n"},{"date":"2019-11-01T13:00:00.000Z","title":"我的 PGP Key","update":"2020-06-10T16:00:00.000Z","_content":"\n# 我的 PGP Key 又双叒叕更换了\n\niseki 总是不能妥善的保管自己的 key 呢\n\n新 Key: [![PGP 0xA213EF73](https://peegeepee.com/badge/orange/A213EF73.svg)](https://peegeepee.com/A213EF73)\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 用户编号:\tiseki <[email protected]>\nComment: 连接时间:\t2020/5/12 16:32\nComment: 过期时间:\t2024/5/11 16:32\nComment: 文件系统:\t4096 位 RSA(绝密密钥可用)\nComment: 用途:\t签名, 仅加密, 正在认证的用户编号\nComment: 指纹:\tCE31AA9B872B869FC6C382F81A121A94A213EF73\n\n\n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\nKQ==\n=oWua\n-----END PGP PUBLIC KEY BLOCK-----\n```\n","source":"_posts/pgpkey.md","raw":"---\ndate: 2019-11-01 21:00:00\ntitle: 我的 PGP Key\ntag: [pgp,openpgp,gpg]\nupdate: 2020-06-11 00:00:00\n---\n\n# 我的 PGP Key 又双叒叕更换了\n\niseki 总是不能妥善的保管自己的 key 呢\n\n新 Key: [![PGP 0xA213EF73](https://peegeepee.com/badge/orange/A213EF73.svg)](https://peegeepee.com/A213EF73)\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 用户编号:\tiseki <[email protected]>\nComment: 连接时间:\t2020/5/12 16:32\nComment: 过期时间:\t2024/5/11 16:32\nComment: 文件系统:\t4096 位 RSA(绝密密钥可用)\nComment: 用途:\t签名, 仅加密, 正在认证的用户编号\nComment: 指纹:\tCE31AA9B872B869FC6C382F81A121A94A213EF73\n\n\n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\nKQ==\n=oWua\n-----END PGP PUBLIC KEY BLOCK-----\n```\n","slug":"pgpkey","published":1,"updated":"2021-09-02T04:05:06.000Z","_id":"clelf1dw3000ro8uzdirf4mqg","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"我的-PGP-Key-又双叒叕更换了\"><a href=\"#我的-PGP-Key-又双叒叕更换了\" class=\"headerlink\" title=\"我的 PGP Key 又双叒叕更换了\"></a>我的 PGP Key 又双叒叕更换了</h1><p>iseki 总是不能妥善的保管自己的 key 呢</p>\n<p>新 Key: <a href=\"https://peegeepee.com/A213EF73\"><img src=\"https://peegeepee.com/badge/orange/A213EF73.svg\" alt=\"PGP 0xA213EF73\"></a></p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">-----BEGIN PGP PUBLIC KEY BLOCK-----</span><br><span class=\"line\">Comment: 用户编号:\tiseki <[email protected]></span><br><span class=\"line\">Comment: 连接时间:\t2020/5/12 16:32</span><br><span class=\"line\">Comment: 过期时间:\t2024/5/11 16:32</span><br><span class=\"line\">Comment: 文件系统:\t4096 位 RSA(绝密密钥可用)</span><br><span class=\"line\">Comment: 用途:\t签名, 仅加密, 正在认证的用户编号</span><br><span class=\"line\">Comment: 指纹:\tCE31AA9B872B869FC6C382F81A121A94A213EF73</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">mQINBF66XycBEAC4QuiiL2FUqHBLTzstrzOi4hHtV2pCIM8K09vEjZbtt73d4reJ</span><br><span class=\"line\">dH98r/HVtgXd2ANfzJkkcnhlJTDLR1iL/3Bu3IOujWEYDx5ULQtW/aEFZdmY7cvQ</span><br><span class=\"line\">wHUV1sJEEclQ4ymXS0oPfpnMVYIWru+/cXkj5jvDuc1pUxwUW0Uwdq8VQ0JWJ8YN</span><br><span class=\"line\">8WB92Kl6Qnxj5gJqLXKT/uANru8Wbe/0kDQSVy38E6g+7NilDpuMDuIsXBQXrjJR</span><br><span class=\"line\">K9ymM5C6mDrfBIi6jSDrFEPw2nnioUPt5iTP3uvjIn+1tb1ZtX2cI9/FMg3dTC0j</span><br><span class=\"line\">FbR0upZz/+2UMv9ynw3gXYI/6tGvqNw0MLRH/gZE80HJPdf60kRNj8cMVo29Yl65</span><br><span class=\"line\">FFq/tyepT/4mkMPEBaoQVkopsGVju195zZwVu0xYKBEjnR7LSZFRaRxAUMgOf7Tq</span><br><span class=\"line\">6DDHi/q9OD2YCWfKdxcmxIvCexGR/OeXQitbCxcwyM2/jgExr/fXAOVBpvAKvMUm</span><br><span class=\"line\">uu0StGSyDCgA1yApIdKMhWVQEuRWpeZtXoEVFraeqIwemPWdGVZSdrh9j4HLhy6Z</span><br><span class=\"line\">dCI7m+frkdXodeAvmYOSwG45RgvT1WxbXvpiMUCBLXflkj+ZhOLMeBZf63mPUGb1</span><br><span class=\"line\">QAJVKY9WA6phq86bWO95B5x9yPwCrDJ/WzKvLAEZ+ionDtOdAWGCVrWELwARAQAB</span><br><span class=\"line\">tBlpc2VraSA8YWRtaW5AaXNla2kuc3BhY2U+iQJUBBMBCgA+FiEEzjGqm4crhp/G</span><br><span class=\"line\">w4L4GhIalKIT73MFAl66XycCGwMFCQeEzgAFCwkIBwIGFQoJCAsCBBYCAwECHgEC</span><br><span class=\"line\">F4AACgkQGhIalKIT73OLUg/+LAIScn/PjTm65gPmNMuDQJea9YOjBThBA/anJIZr</span><br><span class=\"line\">4sDp7teowEeXMKjpwfiCdUoTligzUTkQ5VaWfmDWs7y8lT0ZkEf5pBEjNXBjKxvL</span><br><span class=\"line\">nJ9hs6B52gRb+z8Cn31nYVDaQNbF7FyDOipNHObadV8y2PZoFUg6I67BufeZ8wyJ</span><br><span class=\"line\">gbkdi7sYrJ/G1n9OwvM5cSY329tXEGIsM0fei9te/+dS8iemVN3E9jBjcCVfiod0</span><br><span class=\"line\">WR19hqv+Up59OZR5qh7A5uJ/qYQJBLZmU2FZ6xT8WtZQr3ehoMOenQ2QoXb9lFXv</span><br><span class=\"line\">bIF/9W6PD+YhWLgztBCpg57PGn30P2BTTghlgGTR+8+5CBbSGCrpbpzhH6LPHEiz</span><br><span class=\"line\">LCUMotJYompYXQVZv2H2Zrj4zJLT29RmkZpuYIST5po6b4Jn/3Fe+xh7PkHVdT+d</span><br><span class=\"line\">s+NI2gD/7Oq5+ldtk5cO8dAhVJinnauPzD7GZJfl8aU/WXj4dfefvWGoadOnrmvb</span><br><span class=\"line\">seKAMzYKlDlintELu1XekvVtDW+lX9b+iTrEZPgiXv5yFJ+UpZNEpfTX0PfUoX6F</span><br><span class=\"line\">RjcSeRTpH9gY8fEd4vywcq8fdVOgDmAYR/LpDb9UpgeSZMpp2mJPMOzcKMKFdDEM</span><br><span class=\"line\">C0nuUty/Us0oBuvhIfmxIHOPkhZ7Ob1/95RKpvfOpMIrNPddZlLZiluHgWETRidk</span><br><span class=\"line\">ggC5Ag0EXrpfJwEQAMlMVF2KCmB6+sbaerUVYke0SU/woFa6VnAdnGZb8AdGq9AD</span><br><span class=\"line\">KHzcWtYVPWdGPvTUbqbFZK61tTha19B3f/lT9UodZJ1s4KIw19E67h3+ln51aj+2</span><br><span class=\"line\">fboF5fElJ0uFvN5HL3nEs3P0y1y0Lma04t1/YvnNWcGfwEKuTVWeXx/KqOkoDnDU</span><br><span class=\"line\">lPO18M3gsr2xC5wqGv+5UTC03F2Ga9DKQ+leQeliOYUZSetS4EjbqY5ZsrIItfNk</span><br><span class=\"line\">naErLT7HRgqeCrg/ZzfaiMbU76+WkvANl9A69AAZiQVjwc9Oo7z7u/TLNDK/Ufe3</span><br><span class=\"line\">0oK/J5h91PfkMkvIR+GW58oig7TTUOyIjJIQr+fZTIum93tvCe7eF+GHwMhd+2QY</span><br><span class=\"line\">aLFAhNb+bbcvN7e33N80gQs7+L8915c5ULEng6ROmkl7DL5dfnCgF8vzNzy2Kxlz</span><br><span class=\"line\">wRgeujRbhuS9sNQre0GGNNRHoLvAyCTMdeOnTvq8prxy9QvCO794vcN2Mklk7eLR</span><br><span class=\"line\">Mev9Hs0p1v4PK7t4ObLoVZyLwhlSJJLyd3+X4GdPHH2Tpq7Kc53Fq5iovZxGb4w5</span><br><span class=\"line\">NOYNUrt7TgRTWuA6vXmuI98GlLZ88VUDigL4yFXxiQlMcp8CDC8fz4tfAH5/BlrI</span><br><span class=\"line\">UYfmVVLUDeR7/XGi3fE+ubvdg1czfxseOB/SX+M9OglOA4Yl+SCeJ/L2KvgTABEB</span><br><span class=\"line\">AAGJAjwEGAEKACYWIQTOMaqbhyuGn8bDgvgaEhqUohPvcwUCXrpfJwIbDAUJB4TO</span><br><span class=\"line\">AAAKCRAaEhqUohPvcwahEACOwzinVwP5WcgUtJ9pdnuMjdQZU0h1IWiDd3AAnShm</span><br><span class=\"line\">ndy3Pmy6sa2tVga3Bw4FrVxlTYZ4vQv7efJ39ge5il2cA5S73TltwFdi5PiUzbWX</span><br><span class=\"line\">EvUJcRlRjLbecSQFVB10BHSleVmCAKPsKjRGSww12Qd2WHn5d1pej902NpNQoCIh</span><br><span class=\"line\">7v8hmv0q6RV20nmdllEUtKhVhDvahNOGZEYggTRSsV3pkmQ/d75Aukdr+Uar0ahM</span><br><span class=\"line\">Yn8XIt0pqkQgsZikEJDFqoS+O/p3FDvvtUJEMFZc9UyBhZmWEuHQgKQ2Ndt4Nz/9</span><br><span class=\"line\">kaDZRJIXeoxkIkk447apiXukcp+DgKM6thG2rwQrL3dhC7w3q4nM32U/2M54XFVP</span><br><span class=\"line\">EzGj+Rbf14vLN2vadLYMTCvfbvdnA2cOnfN8Kts6G+UpFP1bEBW3CjORHidDL3Ks</span><br><span class=\"line\">vY+3BQJFmQRyKNrbEZU3iWN9oEWjEUvinwNBJpasPEHz2ukadOo0ZTwmkSOv7wsP</span><br><span class=\"line\">2L+kv7+XlgHMiEMl5Ll43K7NughYsrsy2bYJJQTV+8pFVbwovsm9ar0cbnzVuqpq</span><br><span class=\"line\">GS8EfXaDVnBDmzL7qdSE0KUdhZT9QwQ+J/YrjVpmswY3A+UXLsd4w0E8/sxJtOWB</span><br><span class=\"line\">3yIVxaB6ZXXnNI4ODr/dl42WgstE2sMIqZQVK2OOltbLoOnLrrhqa9X9oHSzR211</span><br><span class=\"line\">KQ==</span><br><span class=\"line\">=oWua</span><br><span class=\"line\">-----END PGP PUBLIC KEY BLOCK-----</span><br></pre></td></tr></table></figure>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"我的-PGP-Key-又双叒叕更换了\"><a href=\"#我的-PGP-Key-又双叒叕更换了\" class=\"headerlink\" title=\"我的 PGP Key 又双叒叕更换了\"></a>我的 PGP Key 又双叒叕更换了</h1><p>iseki 总是不能妥善的保管自己的 key 呢</p>\n<p>新 Key: <a href=\"https://peegeepee.com/A213EF73\"><img src=\"https://peegeepee.com/badge/orange/A213EF73.svg\" alt=\"PGP 0xA213EF73\"></a></p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">-----BEGIN PGP PUBLIC KEY BLOCK-----</span><br><span class=\"line\">Comment: 用户编号:\tiseki <[email protected]></span><br><span class=\"line\">Comment: 连接时间:\t2020/5/12 16:32</span><br><span class=\"line\">Comment: 过期时间:\t2024/5/11 16:32</span><br><span class=\"line\">Comment: 文件系统:\t4096 位 RSA(绝密密钥可用)</span><br><span class=\"line\">Comment: 用途:\t签名, 仅加密, 正在认证的用户编号</span><br><span class=\"line\">Comment: 指纹:\tCE31AA9B872B869FC6C382F81A121A94A213EF73</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">mQINBF66XycBEAC4QuiiL2FUqHBLTzstrzOi4hHtV2pCIM8K09vEjZbtt73d4reJ</span><br><span class=\"line\">dH98r/HVtgXd2ANfzJkkcnhlJTDLR1iL/3Bu3IOujWEYDx5ULQtW/aEFZdmY7cvQ</span><br><span class=\"line\">wHUV1sJEEclQ4ymXS0oPfpnMVYIWru+/cXkj5jvDuc1pUxwUW0Uwdq8VQ0JWJ8YN</span><br><span class=\"line\">8WB92Kl6Qnxj5gJqLXKT/uANru8Wbe/0kDQSVy38E6g+7NilDpuMDuIsXBQXrjJR</span><br><span class=\"line\">K9ymM5C6mDrfBIi6jSDrFEPw2nnioUPt5iTP3uvjIn+1tb1ZtX2cI9/FMg3dTC0j</span><br><span class=\"line\">FbR0upZz/+2UMv9ynw3gXYI/6tGvqNw0MLRH/gZE80HJPdf60kRNj8cMVo29Yl65</span><br><span class=\"line\">FFq/tyepT/4mkMPEBaoQVkopsGVju195zZwVu0xYKBEjnR7LSZFRaRxAUMgOf7Tq</span><br><span class=\"line\">6DDHi/q9OD2YCWfKdxcmxIvCexGR/OeXQitbCxcwyM2/jgExr/fXAOVBpvAKvMUm</span><br><span class=\"line\">uu0StGSyDCgA1yApIdKMhWVQEuRWpeZtXoEVFraeqIwemPWdGVZSdrh9j4HLhy6Z</span><br><span class=\"line\">dCI7m+frkdXodeAvmYOSwG45RgvT1WxbXvpiMUCBLXflkj+ZhOLMeBZf63mPUGb1</span><br><span class=\"line\">QAJVKY9WA6phq86bWO95B5x9yPwCrDJ/WzKvLAEZ+ionDtOdAWGCVrWELwARAQAB</span><br><span class=\"line\">tBlpc2VraSA8YWRtaW5AaXNla2kuc3BhY2U+iQJUBBMBCgA+FiEEzjGqm4crhp/G</span><br><span class=\"line\">w4L4GhIalKIT73MFAl66XycCGwMFCQeEzgAFCwkIBwIGFQoJCAsCBBYCAwECHgEC</span><br><span class=\"line\">F4AACgkQGhIalKIT73OLUg/+LAIScn/PjTm65gPmNMuDQJea9YOjBThBA/anJIZr</span><br><span class=\"line\">4sDp7teowEeXMKjpwfiCdUoTligzUTkQ5VaWfmDWs7y8lT0ZkEf5pBEjNXBjKxvL</span><br><span class=\"line\">nJ9hs6B52gRb+z8Cn31nYVDaQNbF7FyDOipNHObadV8y2PZoFUg6I67BufeZ8wyJ</span><br><span class=\"line\">gbkdi7sYrJ/G1n9OwvM5cSY329tXEGIsM0fei9te/+dS8iemVN3E9jBjcCVfiod0</span><br><span class=\"line\">WR19hqv+Up59OZR5qh7A5uJ/qYQJBLZmU2FZ6xT8WtZQr3ehoMOenQ2QoXb9lFXv</span><br><span class=\"line\">bIF/9W6PD+YhWLgztBCpg57PGn30P2BTTghlgGTR+8+5CBbSGCrpbpzhH6LPHEiz</span><br><span class=\"line\">LCUMotJYompYXQVZv2H2Zrj4zJLT29RmkZpuYIST5po6b4Jn/3Fe+xh7PkHVdT+d</span><br><span class=\"line\">s+NI2gD/7Oq5+ldtk5cO8dAhVJinnauPzD7GZJfl8aU/WXj4dfefvWGoadOnrmvb</span><br><span class=\"line\">seKAMzYKlDlintELu1XekvVtDW+lX9b+iTrEZPgiXv5yFJ+UpZNEpfTX0PfUoX6F</span><br><span class=\"line\">RjcSeRTpH9gY8fEd4vywcq8fdVOgDmAYR/LpDb9UpgeSZMpp2mJPMOzcKMKFdDEM</span><br><span class=\"line\">C0nuUty/Us0oBuvhIfmxIHOPkhZ7Ob1/95RKpvfOpMIrNPddZlLZiluHgWETRidk</span><br><span class=\"line\">ggC5Ag0EXrpfJwEQAMlMVF2KCmB6+sbaerUVYke0SU/woFa6VnAdnGZb8AdGq9AD</span><br><span class=\"line\">KHzcWtYVPWdGPvTUbqbFZK61tTha19B3f/lT9UodZJ1s4KIw19E67h3+ln51aj+2</span><br><span class=\"line\">fboF5fElJ0uFvN5HL3nEs3P0y1y0Lma04t1/YvnNWcGfwEKuTVWeXx/KqOkoDnDU</span><br><span class=\"line\">lPO18M3gsr2xC5wqGv+5UTC03F2Ga9DKQ+leQeliOYUZSetS4EjbqY5ZsrIItfNk</span><br><span class=\"line\">naErLT7HRgqeCrg/ZzfaiMbU76+WkvANl9A69AAZiQVjwc9Oo7z7u/TLNDK/Ufe3</span><br><span class=\"line\">0oK/J5h91PfkMkvIR+GW58oig7TTUOyIjJIQr+fZTIum93tvCe7eF+GHwMhd+2QY</span><br><span class=\"line\">aLFAhNb+bbcvN7e33N80gQs7+L8915c5ULEng6ROmkl7DL5dfnCgF8vzNzy2Kxlz</span><br><span class=\"line\">wRgeujRbhuS9sNQre0GGNNRHoLvAyCTMdeOnTvq8prxy9QvCO794vcN2Mklk7eLR</span><br><span class=\"line\">Mev9Hs0p1v4PK7t4ObLoVZyLwhlSJJLyd3+X4GdPHH2Tpq7Kc53Fq5iovZxGb4w5</span><br><span class=\"line\">NOYNUrt7TgRTWuA6vXmuI98GlLZ88VUDigL4yFXxiQlMcp8CDC8fz4tfAH5/BlrI</span><br><span class=\"line\">UYfmVVLUDeR7/XGi3fE+ubvdg1czfxseOB/SX+M9OglOA4Yl+SCeJ/L2KvgTABEB</span><br><span class=\"line\">AAGJAjwEGAEKACYWIQTOMaqbhyuGn8bDgvgaEhqUohPvcwUCXrpfJwIbDAUJB4TO</span><br><span class=\"line\">AAAKCRAaEhqUohPvcwahEACOwzinVwP5WcgUtJ9pdnuMjdQZU0h1IWiDd3AAnShm</span><br><span class=\"line\">ndy3Pmy6sa2tVga3Bw4FrVxlTYZ4vQv7efJ39ge5il2cA5S73TltwFdi5PiUzbWX</span><br><span class=\"line\">EvUJcRlRjLbecSQFVB10BHSleVmCAKPsKjRGSww12Qd2WHn5d1pej902NpNQoCIh</span><br><span class=\"line\">7v8hmv0q6RV20nmdllEUtKhVhDvahNOGZEYggTRSsV3pkmQ/d75Aukdr+Uar0ahM</span><br><span class=\"line\">Yn8XIt0pqkQgsZikEJDFqoS+O/p3FDvvtUJEMFZc9UyBhZmWEuHQgKQ2Ndt4Nz/9</span><br><span class=\"line\">kaDZRJIXeoxkIkk447apiXukcp+DgKM6thG2rwQrL3dhC7w3q4nM32U/2M54XFVP</span><br><span class=\"line\">EzGj+Rbf14vLN2vadLYMTCvfbvdnA2cOnfN8Kts6G+UpFP1bEBW3CjORHidDL3Ks</span><br><span class=\"line\">vY+3BQJFmQRyKNrbEZU3iWN9oEWjEUvinwNBJpasPEHz2ukadOo0ZTwmkSOv7wsP</span><br><span class=\"line\">2L+kv7+XlgHMiEMl5Ll43K7NughYsrsy2bYJJQTV+8pFVbwovsm9ar0cbnzVuqpq</span><br><span class=\"line\">GS8EfXaDVnBDmzL7qdSE0KUdhZT9QwQ+J/YrjVpmswY3A+UXLsd4w0E8/sxJtOWB</span><br><span class=\"line\">3yIVxaB6ZXXnNI4ODr/dl42WgstE2sMIqZQVK2OOltbLoOnLrrhqa9X9oHSzR211</span><br><span class=\"line\">KQ==</span><br><span class=\"line\">=oWua</span><br><span class=\"line\">-----END PGP PUBLIC KEY BLOCK-----</span><br></pre></td></tr></table></figure>\n"},{"title":"关于Kotlin注解处理器的一些坑","date":"2019-10-13T16:34:14.000Z","updated":"2019-10-13T16:34:14.000Z","_content":"\n1. kapt 1.3.5 存在bug,不能用,连同 kotlin-gradle-plugin 一同降级到 1.3.41\n2. `build.gradle.kts` 中 `dependencies` 需要同时使用 `implementation` 和 `kapt` 引用 `com.google.auto.service:auto-service` ,否则无法识别使用Kotlin编写的注解处理器\n```kotlin\ndependencies{\n implementation(\"com.google.auto.service:auto-service:$googleAutoServiceVersion\")\n kapt(\"com.google.auto.service:auto-service:$googleAutoServiceVersion\")\n}\n```\n3. 如果使用注解的类、函数签名、注解参数等包含顶级包声明的内容,javac可能出现找不到符号异常。不确定是不是bug。由于Windows下jdk可能使用中文locale,idea中Build中文报错可能显示成乱码,可以在Terminal中运行 `gradlew build` 查看错误原因(Terminal的文字编码是正确的)。","source":"_posts/kotlin-kapt-note.md","raw":"---\ntitle: 关于Kotlin注解处理器的一些坑\ndate: 2019-10-14 00:34:14\nupdated: 2019-10-14 00:34:14\ntags: [kotlin,kapt,java,idea,gradle]\n---\n\n1. kapt 1.3.5 存在bug,不能用,连同 kotlin-gradle-plugin 一同降级到 1.3.41\n2. `build.gradle.kts` 中 `dependencies` 需要同时使用 `implementation` 和 `kapt` 引用 `com.google.auto.service:auto-service` ,否则无法识别使用Kotlin编写的注解处理器\n```kotlin\ndependencies{\n implementation(\"com.google.auto.service:auto-service:$googleAutoServiceVersion\")\n kapt(\"com.google.auto.service:auto-service:$googleAutoServiceVersion\")\n}\n```\n3. 如果使用注解的类、函数签名、注解参数等包含顶级包声明的内容,javac可能出现找不到符号异常。不确定是不是bug。由于Windows下jdk可能使用中文locale,idea中Build中文报错可能显示成乱码,可以在Terminal中运行 `gradlew build` 查看错误原因(Terminal的文字编码是正确的)。","slug":"kotlin-kapt-note","published":1,"_id":"clelf1dw70012o8uzglpyd4g0","comments":1,"layout":"post","photos":[],"link":"","content":"<ol>\n<li>kapt 1.3.5 存在bug,不能用,连同 kotlin-gradle-plugin 一同降级到 1.3.41</li>\n<li><code>build.gradle.kts</code> 中 <code>dependencies</code> 需要同时使用 <code>implementation</code> 和 <code>kapt</code> 引用 <code>com.google.auto.service:auto-service</code> ,否则无法识别使用Kotlin编写的注解处理器<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">dependencies{</span><br><span class=\"line\"> implementation(<span class=\"string\">"com.google.auto.service:auto-service:<span class=\"variable\">$googleAutoServiceVersion</span>"</span>)</span><br><span class=\"line\"> kapt(<span class=\"string\">"com.google.auto.service:auto-service:<span class=\"variable\">$googleAutoServiceVersion</span>"</span>)</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li>如果使用注解的类、函数签名、注解参数等包含顶级包声明的内容,javac可能出现找不到符号异常。不确定是不是bug。由于Windows下jdk可能使用中文locale,idea中Build中文报错可能显示成乱码,可以在Terminal中运行 <code>gradlew build</code> 查看错误原因(Terminal的文字编码是正确的)。</li>\n</ol>\n","site":{"data":{}},"excerpt":"","more":"<ol>\n<li>kapt 1.3.5 存在bug,不能用,连同 kotlin-gradle-plugin 一同降级到 1.3.41</li>\n<li><code>build.gradle.kts</code> 中 <code>dependencies</code> 需要同时使用 <code>implementation</code> 和 <code>kapt</code> 引用 <code>com.google.auto.service:auto-service</code> ,否则无法识别使用Kotlin编写的注解处理器<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">dependencies{</span><br><span class=\"line\"> implementation(<span class=\"string\">"com.google.auto.service:auto-service:<span class=\"variable\">$googleAutoServiceVersion</span>"</span>)</span><br><span class=\"line\"> kapt(<span class=\"string\">"com.google.auto.service:auto-service:<span class=\"variable\">$googleAutoServiceVersion</span>"</span>)</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li>如果使用注解的类、函数签名、注解参数等包含顶级包声明的内容,javac可能出现找不到符号异常。不确定是不是bug。由于Windows下jdk可能使用中文locale,idea中Build中文报错可能显示成乱码,可以在Terminal中运行 <code>gradlew build</code> 查看错误原因(Terminal的文字编码是正确的)。</li>\n</ol>\n"},{"title":"使用 Gradle Shadow 插件生成 Fat-Jar","date":"2019-12-08T10:27:59.000Z","updated":"2019-12-08T10:27:59.000Z","_content":"\n# 使用 Gradle Shadow 插件生成 Fat-Jar\n\n在网络上找了好一阵子,最终发现了 [Gradle Shadow] 这个插件,用起来很方便:\n\n首先需要修改 gradle 的 `buildscript` 来引入这个依赖,这个东西 IDEA 默认生成的 Kotlin 项目没有,自己加进去:\n```kotlin\nbuildscript {\n repositories {\n jcenter()\n }\n dependencies {\n // 这里目前的版本号是 5.2.0 ,对应 Gradle 版本 5.x ,较低的版本可能无法使用\n classpath(\"com.github.jengelman.gradle.plugins:shadow:5.2.0\")\n }\n}\n```\n然后在 `plugins` 中加入这个插件就行了:\n```kotlin\nplugins{\n id(\"com.github.johnrengelman.shadow\") version \"5.2.0\"\n}\n```\n\n为了避免生成的 fat-jar 的 `META-INF/MANIFEST.MF` 中缺少 `Main-Class` 项,导致无法直接启动,建议在 `plugins` 中加入 `application`,并配置好相关属性 :\n```kotlin\nplugins{\n application\n}\n\napplication {\n mainClassName = \"yours.MainKt\"\n}\n```\n**Note:** 需要注意的是不建议代码中在顶层包进行任何声明,这在一些插件和库下可能出现问题。 \n(比如 kapt 可能不能正确处理注解,同时由于操作系统 locale 和字符编码问题,你无法在 IDEA 中看到可以理解的错误信息) \n\n最后就可以执行 `.\\gradlew shadowjar` 来生成 fat-jar 了\n\n这些项也可从 `shadowJar` 配置\n\n**Note:** 由于目前版本 `5.2.0` 尚未支持 Kotlin DSL, 如需访问 `shadowJar` 进行更详细的配置(如:[过滤 jar 包中的内容](https://imperceptiblethoughts.com/shadow/configuration/filtering/))\n目前的 Workaround 如下: [>>](https://github.com/johnrengelman/shadow/issues/533#issue-541921197)\n```kotlin\nval shadowJar: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar by tasks\n```\n\n更多的内容建议参考官方 User Guide: [https://imperceptiblethoughts.com/shadow/](https://imperceptiblethoughts.com/shadow/)\n\n项目地址:[https://github.com/johnrengelman/shadow](https://github.com/johnrengelman/shadow)\n\n**Note:** 本文涉及的 Gradle 代码均为 Gradle Kotlin DSL ,视情况可能需要自行修改\n\n\n\n\n[Gradle Shadow]: https://github.com/johnrengelman/shadow","source":"_posts/use-shadow-gradle-plugin-gen-fatjar.md","raw":"---\ntitle: 使用 Gradle Shadow 插件生成 Fat-Jar\ndate: 2019-12-08 18:27:59\nupdated: 2019-12-08 18:27:59\ntags: [gradle,kotlin,jar]\n---\n\n# 使用 Gradle Shadow 插件生成 Fat-Jar\n\n在网络上找了好一阵子,最终发现了 [Gradle Shadow] 这个插件,用起来很方便:\n\n首先需要修改 gradle 的 `buildscript` 来引入这个依赖,这个东西 IDEA 默认生成的 Kotlin 项目没有,自己加进去:\n```kotlin\nbuildscript {\n repositories {\n jcenter()\n }\n dependencies {\n // 这里目前的版本号是 5.2.0 ,对应 Gradle 版本 5.x ,较低的版本可能无法使用\n classpath(\"com.github.jengelman.gradle.plugins:shadow:5.2.0\")\n }\n}\n```\n然后在 `plugins` 中加入这个插件就行了:\n```kotlin\nplugins{\n id(\"com.github.johnrengelman.shadow\") version \"5.2.0\"\n}\n```\n\n为了避免生成的 fat-jar 的 `META-INF/MANIFEST.MF` 中缺少 `Main-Class` 项,导致无法直接启动,建议在 `plugins` 中加入 `application`,并配置好相关属性 :\n```kotlin\nplugins{\n application\n}\n\napplication {\n mainClassName = \"yours.MainKt\"\n}\n```\n**Note:** 需要注意的是不建议代码中在顶层包进行任何声明,这在一些插件和库下可能出现问题。 \n(比如 kapt 可能不能正确处理注解,同时由于操作系统 locale 和字符编码问题,你无法在 IDEA 中看到可以理解的错误信息) \n\n最后就可以执行 `.\\gradlew shadowjar` 来生成 fat-jar 了\n\n这些项也可从 `shadowJar` 配置\n\n**Note:** 由于目前版本 `5.2.0` 尚未支持 Kotlin DSL, 如需访问 `shadowJar` 进行更详细的配置(如:[过滤 jar 包中的内容](https://imperceptiblethoughts.com/shadow/configuration/filtering/))\n目前的 Workaround 如下: [>>](https://github.com/johnrengelman/shadow/issues/533#issue-541921197)\n```kotlin\nval shadowJar: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar by tasks\n```\n\n更多的内容建议参考官方 User Guide: [https://imperceptiblethoughts.com/shadow/](https://imperceptiblethoughts.com/shadow/)\n\n项目地址:[https://github.com/johnrengelman/shadow](https://github.com/johnrengelman/shadow)\n\n**Note:** 本文涉及的 Gradle 代码均为 Gradle Kotlin DSL ,视情况可能需要自行修改\n\n\n\n\n[Gradle Shadow]: https://github.com/johnrengelman/shadow","slug":"use-shadow-gradle-plugin-gen-fatjar","published":1,"_id":"clelf1dw70013o8uzf5shdup6","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"使用-Gradle-Shadow-插件生成-Fat-Jar\"><a href=\"#使用-Gradle-Shadow-插件生成-Fat-Jar\" class=\"headerlink\" title=\"使用 Gradle Shadow 插件生成 Fat-Jar\"></a>使用 Gradle Shadow 插件生成 Fat-Jar</h1><p>在网络上找了好一阵子,最终发现了 <a href=\"https://github.com/johnrengelman/shadow\">Gradle Shadow</a> 这个插件,用起来很方便:</p>\n<p>首先需要修改 gradle 的 <code>buildscript</code> 来引入这个依赖,这个东西 IDEA 默认生成的 Kotlin 项目没有,自己加进去:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">buildscript {</span><br><span class=\"line\"> repositories {</span><br><span class=\"line\"> jcenter()</span><br><span class=\"line\"> }</span><br><span class=\"line\"> dependencies {</span><br><span class=\"line\"> <span class=\"comment\">// 这里目前的版本号是 5.2.0 ,对应 Gradle 版本 5.x ,较低的版本可能无法使用</span></span><br><span class=\"line\"> classpath(<span class=\"string\">"com.github.jengelman.gradle.plugins:shadow:5.2.0"</span>)</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>然后在 <code>plugins</code> 中加入这个插件就行了:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">plugins{</span><br><span class=\"line\"> id(<span class=\"string\">"com.github.johnrengelman.shadow"</span>) version <span class=\"string\">"5.2.0"</span></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>为了避免生成的 fat-jar 的 <code>META-INF/MANIFEST.MF</code> 中缺少 <code>Main-Class</code> 项,导致无法直接启动,建议在 <code>plugins</code> 中加入 <code>application</code>,并配置好相关属性 :</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">plugins{</span><br><span class=\"line\"> application</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\">application {</span><br><span class=\"line\"> mainClassName = <span class=\"string\">"yours.MainKt"</span></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p><strong>Note:</strong> 需要注意的是不建议代码中在顶层包进行任何声明,这在一些插件和库下可能出现问题。<br>(比如 kapt 可能不能正确处理注解,同时由于操作系统 locale 和字符编码问题,你无法在 IDEA 中看到可以理解的错误信息) </p>\n<p>最后就可以执行 <code>.\\gradlew shadowjar</code> 来生成 fat-jar 了</p>\n<p>这些项也可从 <code>shadowJar</code> 配置</p>\n<p><strong>Note:</strong> 由于目前版本 <code>5.2.0</code> 尚未支持 Kotlin DSL, 如需访问 <code>shadowJar</code> 进行更详细的配置(如:<a href=\"https://imperceptiblethoughts.com/shadow/configuration/filtering/\">过滤 jar 包中的内容</a>)<br>目前的 Workaround 如下: <a href=\"https://github.com/johnrengelman/shadow/issues/533#issue-541921197\">>></a></p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">val</span> shadowJar: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar <span class=\"keyword\">by</span> tasks</span><br></pre></td></tr></table></figure>\n\n<p>更多的内容建议参考官方 User Guide: <a href=\"https://imperceptiblethoughts.com/shadow/\">https://imperceptiblethoughts.com/shadow/</a></p>\n<p>项目地址:<a href=\"https://github.com/johnrengelman/shadow\">https://github.com/johnrengelman/shadow</a></p>\n<p><strong>Note:</strong> 本文涉及的 Gradle 代码均为 Gradle Kotlin DSL ,视情况可能需要自行修改</p>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"使用-Gradle-Shadow-插件生成-Fat-Jar\"><a href=\"#使用-Gradle-Shadow-插件生成-Fat-Jar\" class=\"headerlink\" title=\"使用 Gradle Shadow 插件生成 Fat-Jar\"></a>使用 Gradle Shadow 插件生成 Fat-Jar</h1><p>在网络上找了好一阵子,最终发现了 <a href=\"https://github.com/johnrengelman/shadow\">Gradle Shadow</a> 这个插件,用起来很方便:</p>\n<p>首先需要修改 gradle 的 <code>buildscript</code> 来引入这个依赖,这个东西 IDEA 默认生成的 Kotlin 项目没有,自己加进去:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">buildscript {</span><br><span class=\"line\"> repositories {</span><br><span class=\"line\"> jcenter()</span><br><span class=\"line\"> }</span><br><span class=\"line\"> dependencies {</span><br><span class=\"line\"> <span class=\"comment\">// 这里目前的版本号是 5.2.0 ,对应 Gradle 版本 5.x ,较低的版本可能无法使用</span></span><br><span class=\"line\"> classpath(<span class=\"string\">"com.github.jengelman.gradle.plugins:shadow:5.2.0"</span>)</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>然后在 <code>plugins</code> 中加入这个插件就行了:</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">plugins{</span><br><span class=\"line\"> id(<span class=\"string\">"com.github.johnrengelman.shadow"</span>) version <span class=\"string\">"5.2.0"</span></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>为了避免生成的 fat-jar 的 <code>META-INF/MANIFEST.MF</code> 中缺少 <code>Main-Class</code> 项,导致无法直接启动,建议在 <code>plugins</code> 中加入 <code>application</code>,并配置好相关属性 :</p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">plugins{</span><br><span class=\"line\"> application</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\">application {</span><br><span class=\"line\"> mainClassName = <span class=\"string\">"yours.MainKt"</span></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p><strong>Note:</strong> 需要注意的是不建议代码中在顶层包进行任何声明,这在一些插件和库下可能出现问题。<br>(比如 kapt 可能不能正确处理注解,同时由于操作系统 locale 和字符编码问题,你无法在 IDEA 中看到可以理解的错误信息) </p>\n<p>最后就可以执行 <code>.\\gradlew shadowjar</code> 来生成 fat-jar 了</p>\n<p>这些项也可从 <code>shadowJar</code> 配置</p>\n<p><strong>Note:</strong> 由于目前版本 <code>5.2.0</code> 尚未支持 Kotlin DSL, 如需访问 <code>shadowJar</code> 进行更详细的配置(如:<a href=\"https://imperceptiblethoughts.com/shadow/configuration/filtering/\">过滤 jar 包中的内容</a>)<br>目前的 Workaround 如下: <a href=\"https://github.com/johnrengelman/shadow/issues/533#issue-541921197\">>></a></p>\n<figure class=\"highlight kotlin\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">val</span> shadowJar: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar <span class=\"keyword\">by</span> tasks</span><br></pre></td></tr></table></figure>\n\n<p>更多的内容建议参考官方 User Guide: <a href=\"https://imperceptiblethoughts.com/shadow/\">https://imperceptiblethoughts.com/shadow/</a></p>\n<p>项目地址:<a href=\"https://github.com/johnrengelman/shadow\">https://github.com/johnrengelman/shadow</a></p>\n<p><strong>Note:</strong> 本文涉及的 Gradle 代码均为 Gradle Kotlin DSL ,视情况可能需要自行修改</p>\n"},{"title":"在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项","date":"2020-06-10T16:00:00.000Z","updated":"2020-06-10T16:00:00.000Z","_content":"\n# 在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项\n\n可能和 Git for Windows 在安装时的选项有关,需要注意默认情况下 git 可能不会使用 Windows 中安装的 gpg.exe,这必然会导致找不到key。(要不是因为看到了gpg的初始化输出我打死也想不到是这个问题)\n\n`git config --global gpg.program \"c:/Program Files (x86)/GnuPG/bin/gpg.exe\"` 即可,注意看准了自己机器上的路径是啥。\n\n另 `git config commit.gpgsign true` 即可设置该仓库默认签名提交,IDEA里 commit 时就会弹出 Git for windows 的密钥窗口了。","source":"_posts/use-pgp-with-git-on-windows.md","raw":"---\ntitle: 在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项\ndate: 2020-06-11 00:00:00\nupdated: 2020-06-11 00:00:00\ntags: [pgp,git,window]\n---\n\n# 在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项\n\n可能和 Git for Windows 在安装时的选项有关,需要注意默认情况下 git 可能不会使用 Windows 中安装的 gpg.exe,这必然会导致找不到key。(要不是因为看到了gpg的初始化输出我打死也想不到是这个问题)\n\n`git config --global gpg.program \"c:/Program Files (x86)/GnuPG/bin/gpg.exe\"` 即可,注意看准了自己机器上的路径是啥。\n\n另 `git config commit.gpgsign true` 即可设置该仓库默认签名提交,IDEA里 commit 时就会弹出 Git for windows 的密钥窗口了。","slug":"use-pgp-with-git-on-windows","published":1,"_id":"clelf1dwa001go8uzhzizho6q","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"在-Windows-上使用-OpenPGP-签署-Git-提交的一点点注意事项\"><a href=\"#在-Windows-上使用-OpenPGP-签署-Git-提交的一点点注意事项\" class=\"headerlink\" title=\"在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项\"></a>在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项</h1><p>可能和 Git for Windows 在安装时的选项有关,需要注意默认情况下 git 可能不会使用 Windows 中安装的 gpg.exe,这必然会导致找不到key。(要不是因为看到了gpg的初始化输出我打死也想不到是这个问题)</p>\n<p><code>git config --global gpg.program "c:/Program Files (x86)/GnuPG/bin/gpg.exe"</code> 即可,注意看准了自己机器上的路径是啥。</p>\n<p>另 <code>git config commit.gpgsign true</code> 即可设置该仓库默认签名提交,IDEA里 commit 时就会弹出 Git for windows 的密钥窗口了。</p>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"在-Windows-上使用-OpenPGP-签署-Git-提交的一点点注意事项\"><a href=\"#在-Windows-上使用-OpenPGP-签署-Git-提交的一点点注意事项\" class=\"headerlink\" title=\"在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项\"></a>在 Windows 上使用 OpenPGP 签署 Git 提交的一点点注意事项</h1><p>可能和 Git for Windows 在安装时的选项有关,需要注意默认情况下 git 可能不会使用 Windows 中安装的 gpg.exe,这必然会导致找不到key。(要不是因为看到了gpg的初始化输出我打死也想不到是这个问题)</p>\n<p><code>git config --global gpg.program "c:/Program Files (x86)/GnuPG/bin/gpg.exe"</code> 即可,注意看准了自己机器上的路径是啥。</p>\n<p>另 <code>git config commit.gpgsign true</code> 即可设置该仓库默认签名提交,IDEA里 commit 时就会弹出 Git for windows 的密钥窗口了。</p>\n"},{"title":"Hello World","_content":"Welcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).\n\n## Quick Start\n\n### Create a new post\n\n``` bash\n$ hexo new \"My New Post\"\n```\n\nMore info: [Writing](https://hexo.io/docs/writing.html)\n\n### Run server\n\n``` bash\n$ hexo server\n```\n\nMore info: [Server](https://hexo.io/docs/server.html)\n\n### Generate static files\n\n``` bash\n$ hexo generate\n```\n\nMore info: [Generating](https://hexo.io/docs/generating.html)\n\n### Deploy to remote sites\n\n``` bash\n$ hexo deploy\n```\n\nMore info: [Deployment](https://hexo.io/docs/one-command-deployment.html)\n","source":"_drafts/hello-world.md","raw":"---\ntitle: Hello World\n---\nWelcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).\n\n## Quick Start\n\n### Create a new post\n\n``` bash\n$ hexo new \"My New Post\"\n```\n\nMore info: [Writing](https://hexo.io/docs/writing.html)\n\n### Run server\n\n``` bash\n$ hexo server\n```\n\nMore info: [Server](https://hexo.io/docs/server.html)\n\n### Generate static files\n\n``` bash\n$ hexo generate\n```\n\nMore info: [Generating](https://hexo.io/docs/generating.html)\n\n### Deploy to remote sites\n\n``` bash\n$ hexo deploy\n```\n\nMore info: [Deployment](https://hexo.io/docs/one-command-deployment.html)\n","slug":"hello-world","published":0,"date":"2023-02-26T13:13:55.402Z","updated":"2023-02-26T13:13:55.402Z","_id":"clelf5e3o001mo8uzb95m6vny","comments":1,"layout":"post","photos":[],"link":"","content":"<p>Welcome to <a href=\"https://hexo.io/\">Hexo</a>! This is your very first post. Check <a href=\"https://hexo.io/docs/\">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href=\"https://hexo.io/docs/troubleshooting.html\">troubleshooting</a> or you can ask me on <a href=\"https://github.com/hexojs/hexo/issues\">GitHub</a>.</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><h3 id=\"Create-a-new-post\"><a href=\"#Create-a-new-post\" class=\"headerlink\" title=\"Create a new post\"></a>Create a new post</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo new <span class=\"string\">"My New Post"</span></span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/writing.html\">Writing</a></p>\n<h3 id=\"Run-server\"><a href=\"#Run-server\" class=\"headerlink\" title=\"Run server\"></a>Run server</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo server</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/server.html\">Server</a></p>\n<h3 id=\"Generate-static-files\"><a href=\"#Generate-static-files\" class=\"headerlink\" title=\"Generate static files\"></a>Generate static files</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo generate</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/generating.html\">Generating</a></p>\n<h3 id=\"Deploy-to-remote-sites\"><a href=\"#Deploy-to-remote-sites\" class=\"headerlink\" title=\"Deploy to remote sites\"></a>Deploy to remote sites</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo deploy</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/one-command-deployment.html\">Deployment</a></p>\n","site":{"data":{}},"excerpt":"","more":"<p>Welcome to <a href=\"https://hexo.io/\">Hexo</a>! This is your very first post. Check <a href=\"https://hexo.io/docs/\">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href=\"https://hexo.io/docs/troubleshooting.html\">troubleshooting</a> or you can ask me on <a href=\"https://github.com/hexojs/hexo/issues\">GitHub</a>.</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><h3 id=\"Create-a-new-post\"><a href=\"#Create-a-new-post\" class=\"headerlink\" title=\"Create a new post\"></a>Create a new post</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo new <span class=\"string\">"My New Post"</span></span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/writing.html\">Writing</a></p>\n<h3 id=\"Run-server\"><a href=\"#Run-server\" class=\"headerlink\" title=\"Run server\"></a>Run server</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo server</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/server.html\">Server</a></p>\n<h3 id=\"Generate-static-files\"><a href=\"#Generate-static-files\" class=\"headerlink\" title=\"Generate static files\"></a>Generate static files</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo generate</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/generating.html\">Generating</a></p>\n<h3 id=\"Deploy-to-remote-sites\"><a href=\"#Deploy-to-remote-sites\" class=\"headerlink\" title=\"Deploy to remote sites\"></a>Deploy to remote sites</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo deploy</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/docs/one-command-deployment.html\">Deployment</a></p>\n"},{"title":"使用STM32CubeIDE通过SWD调试STM32F103","date":"2020-09-26T11:39:19.000Z","_content":"\n### 要准备的东西\n\n- STM32CubeIDE\n- [OpenOCD](https://gnutoolchains.com/arm-eabi/openocd/ \"Download pre-built OpenOCD for Windows\")\n- CMSIS-DAP 调试器\n- STM32开发板(我用的STM32F103)\n\n### 步骤\n\n去Cube里开个项目,生成代码时注意要在 *Pinout & Configuration / System Core / SYS* 中把 *Debug* 调整成 *Serial Wire*\n\n运行 `openocd -f interface/cmsis-dap.cfg -f target/stm32f1x_stlink.cfg` (注意要确保线路接好,且调试器/开发板 都已经上电允许,否则openocd起不来)\n\nOpenOCD是一种开源调试方案,除此之外还支持大量目标平台和调试器,可在 script 目录下查看\n\n回到CubeIDE,在 *Run / Debug Configuration...* 中添加一个Debug配置,注意GDB端口要和openocd的端口一致\n\n![image-20200926203922007](image-20200926203922007.png)\n\n要确保线路接好, 否则出各种诡异问题emmm,如果调试迟迟不能成功,尝试手动复位,应该可看到OpenOCD输出诸如 `Info : stm32f1x.cpu: external reset detected` 字样","source":"_posts/stm32-with-swd.md","raw":"---\ntitle: 使用STM32CubeIDE通过SWD调试STM32F103\ndate: 2020-09-26 19:39:19\ntags:\t\n---\n\n### 要准备的东西\n\n- STM32CubeIDE\n- [OpenOCD](https://gnutoolchains.com/arm-eabi/openocd/ \"Download pre-built OpenOCD for Windows\")\n- CMSIS-DAP 调试器\n- STM32开发板(我用的STM32F103)\n\n### 步骤\n\n去Cube里开个项目,生成代码时注意要在 *Pinout & Configuration / System Core / SYS* 中把 *Debug* 调整成 *Serial Wire*\n\n运行 `openocd -f interface/cmsis-dap.cfg -f target/stm32f1x_stlink.cfg` (注意要确保线路接好,且调试器/开发板 都已经上电允许,否则openocd起不来)\n\nOpenOCD是一种开源调试方案,除此之外还支持大量目标平台和调试器,可在 script 目录下查看\n\n回到CubeIDE,在 *Run / Debug Configuration...* 中添加一个Debug配置,注意GDB端口要和openocd的端口一致\n\n![image-20200926203922007](image-20200926203922007.png)\n\n要确保线路接好, 否则出各种诡异问题emmm,如果调试迟迟不能成功,尝试手动复位,应该可看到OpenOCD输出诸如 `Info : stm32f1x.cpu: external reset detected` 字样","slug":"stm32-with-swd","published":1,"updated":"2023-02-26T13:27:51.823Z","_id":"clelfam3j0000e8uzg6bf3c5j","comments":1,"layout":"post","photos":[],"link":"","content":"<h3 id=\"要准备的东西\"><a href=\"#要准备的东西\" class=\"headerlink\" title=\"要准备的东西\"></a>要准备的东西</h3><ul>\n<li>STM32CubeIDE</li>\n<li><a href=\"https://gnutoolchains.com/arm-eabi/openocd/\" title=\"Download pre-built OpenOCD for Windows\">OpenOCD</a></li>\n<li>CMSIS-DAP 调试器</li>\n<li>STM32开发板(我用的STM32F103)</li>\n</ul>\n<h3 id=\"步骤\"><a href=\"#步骤\" class=\"headerlink\" title=\"步骤\"></a>步骤</h3><p>去Cube里开个项目,生成代码时注意要在 <em>Pinout & Configuration / System Core / SYS</em> 中把 <em>Debug</em> 调整成 <em>Serial Wire</em></p>\n<p>运行 <code>openocd -f interface/cmsis-dap.cfg -f target/stm32f1x_stlink.cfg</code> (注意要确保线路接好,且调试器/开发板 都已经上电允许,否则openocd起不来)</p>\n<p>OpenOCD是一种开源调试方案,除此之外还支持大量目标平台和调试器,可在 script 目录下查看</p>\n<p>回到CubeIDE,在 <em>Run / Debug Configuration…</em> 中添加一个Debug配置,注意GDB端口要和openocd的端口一致</p>\n<p><img src=\"/2020/09/26/stm32-with-swd/image-20200926203922007.png\" alt=\"image-20200926203922007\"></p>\n<p>要确保线路接好, 否则出各种诡异问题emmm,如果调试迟迟不能成功,尝试手动复位,应该可看到OpenOCD输出诸如 <code>Info : stm32f1x.cpu: external reset detected</code> 字样</p>\n","site":{"data":{}},"excerpt":"","more":"<h3 id=\"要准备的东西\"><a href=\"#要准备的东西\" class=\"headerlink\" title=\"要准备的东西\"></a>要准备的东西</h3><ul>\n<li>STM32CubeIDE</li>\n<li><a href=\"https://gnutoolchains.com/arm-eabi/openocd/\" title=\"Download pre-built OpenOCD for Windows\">OpenOCD</a></li>\n<li>CMSIS-DAP 调试器</li>\n<li>STM32开发板(我用的STM32F103)</li>\n</ul>\n<h3 id=\"步骤\"><a href=\"#步骤\" class=\"headerlink\" title=\"步骤\"></a>步骤</h3><p>去Cube里开个项目,生成代码时注意要在 <em>Pinout & Configuration / System Core / SYS</em> 中把 <em>Debug</em> 调整成 <em>Serial Wire</em></p>\n<p>运行 <code>openocd -f interface/cmsis-dap.cfg -f target/stm32f1x_stlink.cfg</code> (注意要确保线路接好,且调试器/开发板 都已经上电允许,否则openocd起不来)</p>\n<p>OpenOCD是一种开源调试方案,除此之外还支持大量目标平台和调试器,可在 script 目录下查看</p>\n<p>回到CubeIDE,在 <em>Run / Debug Configuration…</em> 中添加一个Debug配置,注意GDB端口要和openocd的端口一致</p>\n<p><img src=\"/2020/09/26/stm32-with-swd/image-20200926203922007.png\" alt=\"image-20200926203922007\"></p>\n<p>要确保线路接好, 否则出各种诡异问题emmm,如果调试迟迟不能成功,尝试手动复位,应该可看到OpenOCD输出诸如 <code>Info : stm32f1x.cpu: external reset detected</code> 字样</p>\n"},{"title":"test-image","date":"2023-02-26T13:26:52.000Z","_content":"","source":"_posts/test-image.md","raw":"---\ntitle: test-image\ndate: 2023-02-26 21:26:52\ntags:\n---\n","slug":"test-image","published":1,"updated":"2023-02-26T13:26:52.529Z","comments":1,"layout":"post","photos":[],"link":"","_id":"clelfegvp0000d4uz7gn0bfaq","content":"","site":{"data":{}},"excerpt":"","more":""}],"PostAsset":[{"_id":"source/_posts/stm32-with-swd/image-20200926203922007.png","slug":"image-20200926203922007.png","post":"clelfam3j0000e8uzg6bf3c5j","modified":0,"renderable":0}],"PostCategory":[],"PostTag":[{"post_id":"clelf1dv80004o8uzd2dp5blj","tag_id":"clelf1dva0006o8uzcwl903bp","_id":"clelf1dvc0008o8uzcbd1e9hw"},{"post_id":"clelf1dv90005o8uzfaqb4oyd","tag_id":"clelf1dvb0007o8uz7h661duo","_id":"clelf1dvc000ao8uzhuwz9r6k"},{"post_id":"clelf1dv90005o8uzfaqb4oyd","tag_id":"clelf1dvc0009o8uz9pzk1gxq","_id":"clelf1dvc000bo8uza7t216vm"},{"post_id":"clelf1dvd000co8uz3ja6fqv5","tag_id":"clelf1dve000do8uzesrz66g5","_id":"clelf1dvf000io8uz52a98v52"},{"post_id":"clelf1dvd000co8uz3ja6fqv5","tag_id":"clelf1dve000eo8uz38sv9131","_id":"clelf1dvf000jo8uz686yfbk4"},{"post_id":"clelf1dvd000co8uz3ja6fqv5","tag_id":"clelf1dve000fo8uz28a2b6dp","_id":"clelf1dvf000ko8uzbso16xmg"},{"post_id":"clelf1dvd000co8uz3ja6fqv5","tag_id":"clelf1dve000go8uz90df00is","_id":"clelf1dvf000lo8uz0asx9hw0"},{"post_id":"clelf1dvd000co8uz3ja6fqv5","tag_id":"clelf1dvf000ho8uzh8dz25ud","_id":"clelf1dvf000mo8uzc9w0g9ax"},{"post_id":"clelf1dvg000no8uzdib5euvz","tag_id":"clelf1dvg000oo8uzfnl4fr1c","_id":"clelf1dvh000po8uz25p07t9k"},{"post_id":"clelf1dw2000qo8uzbynx1i62","tag_id":"clelf1dw4000so8uz9iugb45l","_id":"clelf1dw5000vo8uz0lgq0ejd"},{"post_id":"clelf1dw2000qo8uzbynx1i62","tag_id":"clelf1dw5000to8uz0eeo57kd","_id":"clelf1dw5000wo8uzdgxdbaw2"},{"post_id":"clelf1dw3000ro8uzdirf4mqg","tag_id":"clelf1dw5000uo8uz2wd93o4c","_id":"clelf1dw6000zo8uz7szleqr1"},{"post_id":"clelf1dw3000ro8uzdirf4mqg","tag_id":"clelf1dw5000xo8uzec4ba88a","_id":"clelf1dw60010o8uz13vb7osx"},{"post_id":"clelf1dw3000ro8uzdirf4mqg","tag_id":"clelf1dw6000yo8uz6su663fq","_id":"clelf1dw60011o8uzdk2m7hmn"},{"post_id":"clelf1dw70012o8uzglpyd4g0","tag_id":"clelf1dw4000so8uz9iugb45l","_id":"clelf1dw90018o8uzg5ptak5u"},{"post_id":"clelf1dw70012o8uzglpyd4g0","tag_id":"clelf1dw80014o8uz9hp92qe6","_id":"clelf1dw90019o8uz7km9b24s"},{"post_id":"clelf1dw70012o8uzglpyd4g0","tag_id":"clelf1dw80015o8uzb18343h6","_id":"clelf1dw9001ao8uza0lh05w5"},{"post_id":"clelf1dw70012o8uzglpyd4g0","tag_id":"clelf1dw80016o8uz4emb3n9o","_id":"clelf1dw9001bo8uz2pcn98hq"},{"post_id":"clelf1dw70012o8uzglpyd4g0","tag_id":"clelf1dva0006o8uzcwl903bp","_id":"clelf1dw9001co8uzfntfcn5m"},{"post_id":"clelf1dw70013o8uzf5shdup6","tag_id":"clelf1dva0006o8uzcwl903bp","_id":"clelf1dw9001do8uz1boafi4l"},{"post_id":"clelf1dw70013o8uzf5shdup6","tag_id":"clelf1dw4000so8uz9iugb45l","_id":"clelf1dwa001eo8uzgjqb699d"},{"post_id":"clelf1dw70013o8uzf5shdup6","tag_id":"clelf1dw90017o8uz23wg9thn","_id":"clelf1dwa001fo8uzaatj241f"},{"post_id":"clelf1dwa001go8uzhzizho6q","tag_id":"clelf1dw5000uo8uz2wd93o4c","_id":"clelf1dwb001jo8uz4z8rbafa"},{"post_id":"clelf1dwa001go8uzhzizho6q","tag_id":"clelf1dwb001ho8uzeg403ucd","_id":"clelf1dwb001ko8uzbake8ce5"},{"post_id":"clelf1dwa001go8uzhzizho6q","tag_id":"clelf1dwb001io8uzdnhydcz6","_id":"clelf1dwb001lo8uz3lyl7sev"}],"Tag":[{"name":"gradle","_id":"clelf1dva0006o8uzcwl903bp"},{"name":"pin","_id":"clelf1dvb0007o8uz7h661duo"},{"name":"text","_id":"clelf1dvc0009o8uz9pzk1gxq"},{"name":"github","_id":"clelf1dve000do8uzesrz66g5"},{"name":"action","_id":"clelf1dve000eo8uz38sv9131"},{"name":"nodejs","_id":"clelf1dve000fo8uz28a2b6dp"},{"name":"npm","_id":"clelf1dve000go8uz90df00is"},{"name":"hexo","_id":"clelf1dvf000ho8uzh8dz25ud"},{"name":"dalao","_id":"clelf1dvg000oo8uzfnl4fr1c"},{"name":"kotlin","_id":"clelf1dw4000so8uz9iugb45l"},{"name":"coroutine","_id":"clelf1dw5000to8uz0eeo57kd"},{"name":"pgp","_id":"clelf1dw5000uo8uz2wd93o4c"},{"name":"openpgp","_id":"clelf1dw5000xo8uzec4ba88a"},{"name":"gpg","_id":"clelf1dw6000yo8uz6su663fq"},{"name":"kapt","_id":"clelf1dw80014o8uz9hp92qe6"},{"name":"java","_id":"clelf1dw80015o8uzb18343h6"},{"name":"idea","_id":"clelf1dw80016o8uz4emb3n9o"},{"name":"jar","_id":"clelf1dw90017o8uz23wg9thn"},{"name":"git","_id":"clelf1dwb001ho8uzeg403ucd"},{"name":"window","_id":"clelf1dwb001io8uzdnhydcz6"}]}}