[{"content":"Gitコミットには「Author（作成者）」と「Committer（コミット適用者）」が記録されます。 まれにこれらの変更の必要に迫られることがあるので、後から変更・修正する方法を説明します。\nCommitter と Author の確認方法 git show や git log はデフォルトでは Author しか表示しませんが、オプション --pretty=fuller をつければ Committer も表示されます。 例えば下記のようになります。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ git show HEAD --name-status --pretty=fuller commit 190066b4eb8b7a1b1cda2fecdf5a6b70a1da703b Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash 自分でコードを書いて自分でコミットする場合は上記のようにどちらも同じ人になります。 他の人が git cherry-pick したりすると Author と Committerが 別の人になったりします。 この Author や Committer は基本的に後から変更したりすることはないのですが、ごく稀に変更したくなる場合があります。 原則としてそのような無法なことはしてはいけませんが、時と場合によっては必要になることもあるかもしれません。 今回はそのCommitterとAuthorの名前およびメールアドレス、コミット時刻の変更方法を説明します。\nWarning\nAuthorやCommitterを歴史改変するのはVCSとしてご法度です。 すでにpush済みの履歴を書き換えた場合、サーバーに反映させるには git push --force が必要になり、他の共同開発者に多大な迷惑がかかります。 自分しか使っていないリポジトリなら自由ですが、共同開発のときはよくよく考えて使用してください。\n最新コミットの Committer Author の変更 最新コミットのコミットログを修正するには git commit --amend を使用します。 このコマンドを利用することで Committer, Author を変更できます。 --no-edit も併用すると、いちいちコミットログの修正画面が立ち上がらないので便利です。\ngit push する前なら影響を最小限にして変更ができます。\nCommitter の修正 GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_DATE 変数を利用すればできます。 下記の例では「YAMADA Taro」さんが「日本時間 2025-08-03 01:23」にコミットしたということに修正しています。 メールアドレスは hogehoge@example.com です。 使える時刻のフォーマットはいくつかありますが、好きなものを好みで使えばよいです。 RFC 2822だと Thu, 07 Apr 2005 22:13:13 +0200 のようになります。 ISO 8601だと 2005-04-07T22:13:13 のようになります。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $ git show HEAD --name-status --pretty=fuller commit 190066b4eb8b7a1b1cda2fecdf5a6b70a1da703b Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash $ GIT_COMMITTER_DATE=\u0026#34;2025-08-03T01:23:45+09:00\u0026#34; GIT_COMMITTER_NAME=\u0026#34;YAMADA TARO\u0026#34; GIT_COMMITTER_EMAIL=\u0026#34;hogehoge@example.com\u0026#34; git commit --amend --no-edit [detached HEAD 57466d8] test: Fix remote_helper test error for long $PWD Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; Date: Thu Mar 12 08:31:19 2026 +0100 1 file changed, 2 insertions(+), 2 deletions(-) $ git show HEAD --name-status --pretty=fuller commit 57466d8ad3ad20a248a3202842715c4b7a3961c6 (HEAD) Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: YAMADA TARO \u0026lt;hogehoge@example.com\u0026gt; CommitDate: Sun Aug 3 01:23:45 2025 +0900 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash Author の修正 Author の変更は --author --date を使用します。 --author のフォーマットは USER Name \u0026lt;hogehoge@example.com\u0026gt;　のようになります。\n下記の例では「YAMADA TARO」さんが、書いたコードを「日本時間 2025-08-03 01:23」にコミットしたということに修正しています。 ただし、このままAuthorを変更するとCommitterが今現在のアカウントに更新されてしまいます。 下記の例ではJoel RosdahlさんからNAGAYASU ShinyaさんにCommitterが更新されています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $ git show HEAD --name-status --pretty=fuller commit 190066b4eb8b7a1b1cda2fecdf5a6b70a1da703b Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash $ git commit --amend --no-edit \\ --author=\u0026#34;YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt;\u0026#34; \\ --date=\u0026#34;2025-01-23T01:23:45+09:00\u0026#34; [detached HEAD 110f2d5] test: Fix remote_helper test error for long $PWD Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; Date: Thu Jan 23 01:23:45 2025 +0900 1 file changed, 2 insertions(+), 2 deletions(-) $ git show HEAD --name-status --pretty=fuller commit 110f2d52243d3bdf9a4429d28189453d57a2c9ed (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Jan 23 01:23:45 2025 +0900 Commit: NAGAYASU Shinya \u0026lt;nagayasu_shinya@yahoo.co.jp\u0026gt; CommitDate: Thu Mar 19 23:56:57 2026 +0900 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash これは GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE を併用すれば解決できます。 いまの Committer の値をこれらの環境変数に設定することで同じ設定で上書きします。 下記の例では git show --pretty='format:%cn' のようにしてそれらの値を取得しています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 $ git show HEAD --name-status --pretty=fuller commit 190066b4eb8b7a1b1cda2fecdf5a6b70a1da703b (HEAD) Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash $ GIT_COMMITTER_NAME=\u0026#34;$( git show --pretty=\u0026#39;format:%cn\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_EMAIL=\u0026#34;$(git show --pretty=\u0026#39;format:%ce\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_DATE=\u0026#34;$( git show --pretty=\u0026#39;format:%cd\u0026#39; | head -n1)\u0026#34; \\ git commit --amend --no-edit --author=\u0026#34;YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt;\u0026#34; --date=\u0026#34;2025-01-23T01:23:45+09:00\u0026#34; [detached HEAD 94b4981] test: Fix remote_helper test error for long $PWD Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; Date: Thu Jan 23 01:23:45 2025 +0900 1 file changed, 2 insertions(+), 2 deletions(-) $ git show HEAD --name-status --pretty=fuller commit 94b498124ff1456eb753ed3537920e3e8e218ff5 (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Jan 23 01:23:45 2025 +0900 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash もっと昔のコミットの修正 今までの例は最新のコミットの修正でした。2つ以上前のコミットも変更したいこともあるかもしれません。 その場合は git rebase -i を利用します。\n例として下記の3つのコミットを修正します。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $ git log --pretty=fuller --name-status commit 190066b4eb8b7a1b1cda2fecdf5a6b70a1da703b (HEAD) Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash commit edc01c08f0f5e7e1808cc80dccfece9c59469368 Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Thu Mar 12 08:24:32 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:24:32 2026 +0100 chore: Improve log messages for Unix socket connect failure Related to #1697. M test/storage/helper/main.cpp commit e7bf8e7fea2460226ad80ab08d2b0ece3b1bc632 Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Wed Mar 11 21:21:44 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Wed Mar 11 21:21:44 2026 +0100 ci: Add macOS 15/26 builds Also bump Xcode version for macOS 14. M .github/workflows/build.yaml まず git rebase -i にて3つのコミットを編集できるようにします。\n1 git rebase -i HEAD~3^ 変更したいコミットを edit に設定します。このときのコミットIDは後で必要になるのでメモしておいてください。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 pick 801d828 chore: Improve log messages for Unix socket connect failure edit e7bf8e7 ci: Add macOS 15/26 builds edit edc01c0 chore: Improve log messages for Unix socket connect failure edit 190066b test: Fix remote_helper test error for long $PWD # Rebase dd994d2..190066b onto dd994d2 (4 commands) # # Commands: # p, pick \u0026lt;commit\u0026gt; = use commit # r, reword \u0026lt;commit\u0026gt; = use commit, but edit the commit message # e, edit \u0026lt;commit\u0026gt; = use commit, but stop for amending # s, squash \u0026lt;commit\u0026gt; = use commit, but meld into previous commit # f, fixup [-C | -c] \u0026lt;commit\u0026gt; = like \u0026#34;squash\u0026#34; but keep only the previous # commit\u0026#39;s log message, unless -C is used, in which case # keep only this commit\u0026#39;s message; -c is same as -C but # opens the editor # x, exec \u0026lt;command\u0026gt; = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with \u0026#39;git rebase --continue\u0026#39;) # d, drop \u0026lt;commit\u0026gt; = remove commit # l, label \u0026lt;label\u0026gt; = label current HEAD with a name # t, reset \u0026lt;label\u0026gt; = reset HEAD to a label # m, merge [-C \u0026lt;commit\u0026gt; | -c \u0026lt;commit\u0026gt;] \u0026lt;label\u0026gt; [# \u0026lt;oneline\u0026gt;] # create a merge commit using the original merge commit\u0026#39;s # message (or the oneline, if no original merge commit was # specified); use -c \u0026lt;commit\u0026gt; to reword the commit message # u, update-ref \u0026lt;ref\u0026gt; = track a placeholder for the \u0026lt;ref\u0026gt; to be updated # to this position in the new commits. The \u0026lt;ref\u0026gt; is # updated at the end of the rebase # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. 古いコミットから１つずつ修正していきます。 いま時点でrebaseする３つのコミットの中で1番古いコミットをHEADが指しているはずです。\n1 2 3 4 5 6 7 8 9 10 11 12 $ git show --pretty=fuller --name-status commit e7bf8e7fea2460226ad80ab08d2b0ece3b1bc632 (HEAD) Author: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; AuthorDate: Wed Mar 11 21:21:44 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Wed Mar 11 21:21:44 2026 +0100 ci: Add macOS 15/26 builds Also bump Xcode version for macOS 14. M .github/workflows/build.yaml このコミットをこれまで説明してきた方法で修正します。 ここでもコミットを修正するとCommitterが今現在のGitアカウントに更新されてしまうので、 下記の例ではもとのGit コミットID（e7bf8e7）のCommitterを指定しています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ GIT_COMMITTER_NAME=\u0026#34;$( git show e7bf8e7 --pretty=\u0026#39;format:%cn\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_EMAIL=\u0026#34;$(git show e7bf8e7 --pretty=\u0026#39;format:%ce\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_DATE=\u0026#34;$( git show e7bf8e7 --pretty=\u0026#39;format:%cd\u0026#39; | head -n1)\u0026#34; \\ git commit --amend --no-edit --author=\u0026#34;YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt;\u0026#34; [detached HEAD 545fa368] ci: Add macOS 15/26 builds Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; Date: Wed Mar 11 21:21:44 2026 +0100 1 file changed, 10 insertions(+), 1 deletion(-) $ git show --pretty=fuller --name-status commit 545fa36809d77b5d7ab76047aef12a670d6156c4 (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Wed Mar 11 21:21:44 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Wed Mar 11 21:21:44 2026 +0100 ci: Add macOS 15/26 builds Also bump Xcode version for macOS 14. M .github/workflows/build.yaml コミットの修正が完了したら次のコミットへ進みます。\n1 git rebase --continue あとは繰り返しです。ここでもCommitterが今現在のGitアカウントに更新されてしまっているので、 明示的に rebase前のコミットID（edc01c0）の情報で上書きが必要です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ GIT_COMMITTER_NAME=\u0026#34;$( git show edc01c0 --pretty=\u0026#39;format:%cn\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_EMAIL=\u0026#34;$(git show edc01c0 --pretty=\u0026#39;format:%ce\u0026#39; | head -n1)\u0026#34; \\ GIT_COMMITTER_DATE=\u0026#34;$( git show edc01c0 --pretty=\u0026#39;format:%cd\u0026#39; | head -n1)\u0026#34; \\ git commit --amend --no-edit --author=\u0026#34;YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt;\u0026#34; [detached HEAD 87f9ee82] chore: Improve log messages for Unix socket connect failure Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; Date: Thu Mar 12 08:24:32 2026 +0100 1 file changed, 4 insertions(+), 1 deletion(-) $ git show --pretty=fuller --name-status commit 87f9ee826c8b5a97503dba2d8a1f44e4174b2468 (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Mar 12 08:24:32 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:24:32 2026 +0100 chore: Improve log messages for Unix socket connect failure Related to #1697. M test/storage/helper/main.cpp すべての edit が終わり Successfully rebased and updated refs/heads/... と表示されれば完了です。 最終的なログを確認すると、指定したコミットのAuthorが変更されているはずです。 最終的には下記のようになります。Authorを YAMADA Taroさんに変更できました。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 git log --name-status --pretty=fuller commit 1cc0e6a49abd43a1949f3ad260c20ba54613775d (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash commit 87f9ee826c8b5a97503dba2d8a1f44e4174b2468 Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Mar 12 08:24:32 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:24:32 2026 +0100 chore: Improve log messages for Unix socket connect failure Related to #1697. M test/storage/helper/main.cpp commit 545fa36809d77b5d7ab76047aef12a670d6156c4 Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Wed Mar 11 21:21:44 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Wed Mar 11 21:21:44 2026 +0100 ci: Add macOS 15/26 builds Also bump Xcode version for macOS 14. M .github/workflows/build.yaml git filter-repo 2, 3 個程度のコミットの修正なら git commit --amend でもいいと思いますが、数が多くなると非効率です。 そこで、さらに強力なツールとしてgit filter-repoがあります。\n注意点 このツールには注意点があるので先にその点を述べておきます。 このツールを実行すると下記のようにリモートのoriginを削除してしまいます。これは歴史改変したコミットを意図せずpushしないようにするための措置でしょう。\n1 2 3 NOTICE: Removing \u0026#39;origin\u0026#39; remote; see \u0026#39;Why is my origin removed?\u0026#39; in the manual if you want to push back there. (was https://github.com/your-username/your-repository.git) あらかじめremoteの情報をメモしておき、git remote add で再度リモートを追加すればよいでしょう。\n1 2 3 $ git remote -v origin https://github.com/ccache/ccache.git (fetch) origin https://github.com/ccache/ccache.git (push) 1 git add remote origin https://github.com/ccache/ccache.git 使い方 さて、ツールの使い方に戻ります。 まずは wget で Python のコードをダウンロードします。\n1 wget https://raw.githubusercontent.com/newren/git-filter-repo/refs/heads/main/git-filter-repo 下記にAuthorを変更する例を示します。git commit --amendのときと違ってCommitterは変更されません。 また、--refs HEAD^..HEAD のようにコミットを明示しないと過去すべての履歴を修正してしまうので注意してください。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 DT=\u0026#39;2025-01-23T01:23:45+09:00\u0026#39; \u0026amp;\u0026amp; python3 git-filter-repo --commit-callback \u0026#34;commit.author_name = b\u0026#39;YAMADA Taro\u0026#39;; commit.author_email = b\u0026#39;hogehoge@example.com\u0026#39;; commit.author_date = b\u0026#39;$(date -d $DT +%s) $(date -d $DT +%z)\u0026#39;\u0026#34; --force --refs HEAD^..HEAD Parsed 1 commits New history written in 0.02 seconds... HEAD is now at 94b49812 test: Fix remote_helper test error for long $PWD Completely finished after 0.03 seconds. $ git show --pretty=fuller --name-status commit 94b498124ff1456eb753ed3537920e3e8e218ff5 (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Jan 23 01:23:45 2025 +0900 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash ここで、時刻指定はUNIX時間（エポック秒）とタイムゾーンで指定する必要があります。 ISO 8601から変換するには下記のようにdateを使えばできます。\n1 2 3 4 $ date -d 2025-01-23T03:23:45+09:00 +%s 1737570225 $ date -d 2025-01-23T03:23:45+09:00 +%z +0900 複数のコミットを修正するのもかんたんです。git commit --amendのときのように git rebase -iで何回もコマンドを実行しなくてよいので楽ですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 $ python3 git-filter-repo --commit-callback \u0026#34;commit.author_name = b\u0026#39;YAMADA Taro\u0026#39;; commit.author_email = b\u0026#39;hogehoge@example.com\u0026#39;\u0026#34; --force --refs HEAD~3..HEAD Parsed 3 commits New history written in 0.02 seconds... HEAD is now at 1cc0e6a4 test: Fix remote_helper test error for long $PWD Completely finished after 0.03 seconds. $ git log --name-status --pretty=fuller commit 1cc0e6a49abd43a1949f3ad260c20ba54613775d (HEAD) Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Mar 12 08:31:19 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:44:12 2026 +0100 test: Fix remote_helper test error for long $PWD Use relative Unix socket paths in tests to avoid overflowing the Unix socket name length limit when $PWD is long. Fixes #1697. M test/suites/remote_helper.bash commit 87f9ee826c8b5a97503dba2d8a1f44e4174b2468 Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Thu Mar 12 08:24:32 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Thu Mar 12 08:24:32 2026 +0100 chore: Improve log messages for Unix socket connect failure Related to #1697. M test/storage/helper/main.cpp commit 545fa36809d77b5d7ab76047aef12a670d6156c4 Author: YAMADA Taro \u0026lt;hogehoge@example.com\u0026gt; AuthorDate: Wed Mar 11 21:21:44 2026 +0100 Commit: Joel Rosdahl \u0026lt;joel@rosdahl.net\u0026gt; CommitDate: Wed Mar 11 21:21:44 2026 +0100 ci: Add macOS 15/26 builds Also bump Xcode version for macOS 14. M .github/workflows/build.yaml Committerを変更するときも同様です。commit.committer_name commit.committer_email commit.committer_date を使用します。 指定方法はAuthorのときと同じです。\nまとめ Gitの禁じ手である、Committer, Author およびその時刻の改変の方法を説明しました。 めったに使うことはないですが、使う際は慎重に実施しましょう。\n","permalink":"https://nagayasu-shinya.github.io/posts/git-rewrite-commit-metadata/","summary":"\u003cp\u003eGitコミットには「Author（作成者）」と「Committer（コミット適用者）」が記録されます。\nまれにこれらの変更の必要に迫られることがあるので、後から変更・修正する方法を説明します。\u003c/p\u003e","title":"GitのCommitterとAuthorを変更する"},{"content":"ターミナルプロンプトをカスタマイズしていろいろな情報を表示できるようにする oh-my-posh を紹介します。 プロンプトに処理結果や処理時間、Gitステータスなどを表示できるようになります。\nどのような見た目になるか Oh My Posh を使うとどのようになるのかイメージがわかないかもしれないので先に使用例を挙げます。 確認環境は WSL上のUbuntuおよび素のUbuntuです。バージョンは下記の通り。\n1 2 3 4 5 $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=24.04 DISTRIB_CODENAME=noble DISTRIB_DESCRIPTION=\u0026#34;Ubuntu 24.04.2 LTS\u0026#34; 下記の例ではOS名、コマンドの処理時間、処理結果が表示されています。いちいち time や echo $?しなくていいので便利です。\nさらにGitHubのディレクトリではこんな感じです。GitHubアイコンとブランチ名、ステータスがわかるようになります。\nPython仮想環境だとバージョンが表示されたりもします。\nこのようにプロンプトを便利な表現にできます。\n導入方法 インストール まずはインストールします。公式ドキュメントにインストール方法の記載あります。特に難しいことはないです。 公式サイトにある Set up your terminal の手順に沿って実行すればよいです。 Linuxなら下記のとおりです(2025-06-22現在)。\n1 2 3 $ curl -s https://ohmyposh.dev/install.sh | bash -s $ which oh-my-posh /home/shinya/bin/oh-my-posh NERD FONTS のダウンロード 最初の例でも示したようにGitHubやPythonのアイコンも表示可能ですのでそれらに対応したフォントが必要です。 ここでは開発者向けにアイコンを追加したフォント群のNerds Fonts を利用します。 お好みで選べばOKですが、今回の例では日本語もいい感じに表示してくれるBizin Gothicを使用しています。 どのようなフォントかは窓の杜の 日本人プログラマー向けコーディングフォント「Bizin Gothic」が無償公開 などを参照ください。\nフォントのインストールはお使いのOSに合わせてやってください。通常と変わらない方法でOKです。よくわからなければググれば出てきます。 ちなみにWSLでのフォントの指定は下記のようにできます。今回は Bizin Gothic Discord NFを使用しています。NFは NERD FONTSの略です。\nテーマのダウンロード 公式サイトにたくさんのテーマが置いてあります。下記の手順でダウンロードします。\n1 2 3 4 5 mkdir ~/.poshthemes wget https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/themes.zip -O ~/.poshthemes/themes.zip unzip ~/.poshthemes/themes.zip -d ~/.poshthemes chmod u+rw ~/.poshthemes/*.omp.* rm ~/.poshthemes/themes.zip テーマの反映 下記のコマンドにてテーマのjsonファイルを指定すれば反映されます。 ~/.poshthemes/ 以下にたくさんテーマがあるのでお好みのものを指定すればOKです。\n1 eval \u0026#34;$(oh-my-posh init bash --config ~/.poshthemes/hoge.json)\u0026#34; 参考に、試しにいくつか設定してみた例を示します。コマンド実行すると即時で反映されてプロンプトが変化します。いろいろなjsonファイルで試してお気に入りを見つけてみてください。\nまた、公式サイトのThemesにもたくさん表示例があるのでそちらも参考になると思います。\nカスタマイズ方法 既存のテーマで飽き足らない場合は自分でカスタマイズすることも可能です。 公式サイトのConfigurationの説明に沿ってjsonファイルを修正すればよいです。 結構大変かもしれませんが凝りたい人はやってみてください。\nNerd Fontsのユニコードの確認 テーマのjsonファイル内で、NERD FONTSのアイコンはユニコードで指定されています。 例えばPythonのアイコンは \\ue235となっています。 このユニコードだけみてもどんなアイコンかわからないのでNerd Fonts Cheat Sheet のチートシートを使うと便利です。 たとえば \\ue235 を入力すると下記のようにPythonのアイコンが表示されます（ユニコードエスケープシーケンス\\u は省いてください）。\nその他は公式サイト見ながらカットアンドトライやればできると思います。頑張ってください。\nテーマのサンプル 参考までに手元でカットアンドトライしてみたテーマのjsonを貼っておきます。冒頭にて紹介した表示例になります。 もとのテーマファイルがzsh向けだったのをbashむけにちょこちょこ修正したものです、細かいところはまちがっているかもなのであくまで参考までです。\nテーマのサンプル 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 { \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\u0026#34;, \u0026#34;blocks\u0026#34;: [ { \u0026#34;alignment\u0026#34;: \u0026#34;left\u0026#34;, \u0026#34;segments\u0026#34;: [ { \u0026#34;background\u0026#34;: \u0026#34;#d3d7cf\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#000000\u0026#34;, \u0026#34;leading_diamond\u0026#34;: \u0026#34;\\ue0b2\u0026#34;, \u0026#34;style\u0026#34;: \u0026#34;diamond\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .WSL }}WSL{{ end }}{{.Icon}} \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;os\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#91ddff\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#100e23\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;home_icon\u0026#34;: \u0026#34;~\u0026#34;, \u0026#34;style\u0026#34;: \u0026#34;full\u0026#34; }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; \\uf07c {{ .Path }} \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;path\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#4e9a06\u0026#34;, \u0026#34;background_templates\u0026#34;: [ \u0026#34;{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9966{{ end }}\u0026#34;, \u0026#34;{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\u0026#34;, \u0026#34;{{ if gt .Ahead 0 }}#89d1dc{{ end }}\u0026#34;, \u0026#34;{{ if gt .Behind 0 }}#4e9a06{{ end }}\u0026#34; ], \u0026#34;foreground\u0026#34;: \u0026#34;#000000\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;branch_icon\u0026#34;: \u0026#34;\\uf126 \u0026#34;, \u0026#34;fetch_stash_count\u0026#34;: true, \u0026#34;fetch_status\u0026#34;: true, \u0026#34;fetch_upstream_icon\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ .UpstreamIcon }} {{ .HEAD }} {{if .BranchStatus }}{{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;git\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#689f63\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#ffffff\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;fetch_version\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \\ue718 \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;node\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#00acd7\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#111111\u0026#34;, \u0026#34;invert_powerline\u0026#34;: true, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;fetch_version\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue627 \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;go\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#4063D8\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#111111\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;fetch_version\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue624 \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;julia\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#FFDE57\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#111111\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;display_mode\u0026#34;: \u0026#34;files\u0026#34;, \u0026#34;fetch_virtual_env\u0026#34;: false }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue235 \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;python\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#AE1401\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#ffffff\u0026#34;, \u0026#34;invert_powerline\u0026#34;: true, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b2\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;display_mode\u0026#34;: \u0026#34;files\u0026#34;, \u0026#34;fetch_version\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue791 \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;ruby\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#FEAC19\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#ffffff\u0026#34;, \u0026#34;invert_powerline\u0026#34;: true, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b2\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;display_mode\u0026#34;: \u0026#34;files\u0026#34;, \u0026#34;fetch_version\u0026#34;: false }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\uf0e7\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;azfunc\u0026#34; }, { \u0026#34;background_templates\u0026#34;: [ \u0026#34;{{if contains \\\u0026#34;default\\\u0026#34; .Profile}}#FFA400{{end}}\u0026#34;, \u0026#34;{{if contains \\\u0026#34;jan\\\u0026#34; .Profile}}#f1184c{{end}}\u0026#34; ], \u0026#34;foreground\u0026#34;: \u0026#34;#ffffff\u0026#34;, \u0026#34;invert_powerline\u0026#34;: true, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b2\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;display_default\u0026#34;: false }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \\ue7ad \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;aws\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#ffff66\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#111111\u0026#34;, \u0026#34;invert_powerline\u0026#34;: true, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b2\u0026#34;, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; \\uf0ad \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;root\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#a9a9a9\u0026#34;, \u0026#34;foreground\u0026#34;: \u0026#34;#000000\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;always_enabled\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ .FormattedMs }}\u0026#34;, \u0026#34;trailing_diamond\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;executiontime\u0026#34; }, { \u0026#34;background\u0026#34;: \u0026#34;#007ACC\u0026#34;, \u0026#34;background_templates\u0026#34;: [ \u0026#34;{{ if gt .Code 0 }}#cc2222{{ end }}\u0026#34; ], \u0026#34;foreground\u0026#34;: \u0026#34;#d3d7cf\u0026#34;, \u0026#34;powerline_symbol\u0026#34;: \u0026#34;\\ue0b0\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;always_enabled\u0026#34;: true }, \u0026#34;style\u0026#34;: \u0026#34;powerline\u0026#34;, \u0026#34;template\u0026#34;: \u0026#34; {{ if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} \u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;status\u0026#34; } ], \u0026#34;type\u0026#34;: \u0026#34;prompt\u0026#34; } ], \u0026#34;console_title_template\u0026#34;: \u0026#34;{{ .Shell }} in {{ .Folder }}\u0026#34;, \u0026#34;final_space\u0026#34;: true, \u0026#34;version\u0026#34;: 3 } まとめ 今回はプロンプトをかっこよくする Oh My Posh を紹介しました。 プロンプトをビジュアライズして実行時間や実行結果、Gitのステータスなどをわかりやすく表示できます。カスタマイズ性もあるのでご自分の好みに合わせてかっこよくしてみてください！\n","permalink":"https://nagayasu-shinya.github.io/posts/terminal-prompt-oh-my-posh/","summary":"\u003cp\u003eターミナルプロンプトをカスタマイズしていろいろな情報を表示できるようにする oh-my-posh を紹介します。\nプロンプトに処理結果や処理時間、Gitステータスなどを表示できるようになります。\u003c/p\u003e","title":"ターミナルのプロンプトをかっこよくする！ | Oh My Posh"},{"content":"Jenkins のリリースフローで手動ビルドのリリースを禁止したいときは通常Jenkinsユーザーの権限を制限することで実現するかと思います。 さらに念を入れて手動ビルド自体を禁止する方法を説明します。\n手動ビルドを禁止するJenkinsfile when と triggeredBy を使えば、そのビルドのトリガーが手動（ユーザー）なのかポーリングなのか判定できます。 そこで error や false で止めてしまえばよいです。\n下記の例は、人が手動でビルドボタンを押したときにビルドを中断させる例です。これで手動ビルドする不届き者を排除できます。\n1 2 3 4 5 6 7 8 9 10 11 12 stage (\u0026#39;トリガーチェック\u0026#39;) { when { triggeredBy cause: \u0026#34;UserIdCause\u0026#34; } steps { script { echo \u0026#34;Do not execute build triggers manually.\u0026#34; currentBuild.result = \u0026#39;NOT_BUILT\u0026#39; sh \u0026#39;false\u0026#39; // 明示的にビルドを失敗させる } } } その他のビルドトリガの判定 ちなみに、Gitなどのポーリングの場合は下記で捕まえられます。\n1 2 3 4 5 6 7 8 9 stage (\u0026#39;トリガーチェック\u0026#39;) { // こっちはSCMポーリングの場合. when { triggeredBy \u0026#39;SCMTrigger\u0026#39; } steps { echo \u0026#34;Running because triggered by a SCM Trigger\u0026#34; } } 他には下記のトリガがあるそうです。最後のものは特定のユーザが手動ビルドしたときですね。この例ではvlindeさん。\nwhen { triggeredBy 'TimerTrigger' } when { triggeredBy 'BuildUpstreamCause' } when { triggeredBy cause: \u0026quot;UserIdCause\u0026quot;, detail: \u0026quot;vlinde\u0026quot; }\n公式サイトのPipeline - whenに詳細な説明があります。 もっと複雑な処理をしたい場合は参照してください。\nまとめ Jenkinsにて手動ビルドされたときにビルドジョブを中断する方法を書きました。 ユーザー権限で制限するのが普通ですが、さらにJenkinsfileでも禁止しておけば安心ですね。\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-manual-trigger-prevention/","summary":"\u003cp\u003eJenkins のリリースフローで手動ビルドのリリースを禁止したいときは通常Jenkinsユーザーの権限を制限することで実現するかと思います。\nさらに念を入れて手動ビルド自体を禁止する方法を説明します。\u003c/p\u003e","title":"Jenkins で手動ビルドを禁止する書き方"},{"content":"WSLで大抵のことは完結できるようになってきましたが、ときどきWindows側の.exeを使いたくなるときがあります。 その方法を説明します。\n例えばUSB接続したAndroid端末を制御するにはAndroid デバッグツールadbを使います。 ですがWSLのadbを実行してもデバイスを見つけられず下記のようなエラーになります。\n1 2 $ adb devices adb: no devices/emulators found このような場合はWSL内のツールでは操作は難しいので素直にWindows側のadb.exeを実行したほうが楽です。 単純に使うだけなら.exeをWSLから実行すればいいのですがいくつかはまりポイントがあります。 そこで今回は Windows ネイティブの adb.exe を例に WSL からWindowsの .exeを使うコツを説明します。 今回は adb.exeを例にしていますが、別のツールでも基本的に一緒のはずです。 ぜひ参考にしてください。\nWindows 用の. exe ダウンロード まずなにはともあれ .exe が必要です。adbは、SDK Platform-Tools からダウンロードします。\nplatform-tools-latest-windows.zip をダウンロードしたら、任意のフォルダに展開します。 その中には adb.exe や fastboot.exe が含まれているはずです。 奥場所はどこのフォルダでもいいのですが、Program Filesのようなフォルダ名にスペースがある 正気を疑うネーミングの ところは避けたほうがよいです。 今回はc:\\Programs\\platform-tools\\に置いたことにします。 エスケープが面倒なのでスペースをフォルダ名、ファイル名に入れないほうが幸せになれると思います。\nさらにWindows環境変数（not WSL）のPATHにも設定しておきます。 【Windows 10／11】Path環境変数の設定で「あのコマンド、どこだっけ？」をなくす、Windows効率向上の最強テクニックの記事が参考になるかと思います。\nWSL のパス設定 WSL はデフォルトで Windows 側のパス設定を引き継ぐ仕様なので特に何もせずとも adb.exeが使えるはずです。 下記のように which コマンドで adb.exe が見つかればOKです。\n1 2 $ which adb.exe /mnt/c/Programs/platform-tools/adb.exe もし使えない場合は .bashrc などで PATH 変数に追記してください。 今回の例だと下記のように記載すれば良いです。\n1 PATH=$PATH:\u0026#39;/mnt/c/Programs/platform-tools/\u0026#39; 文字コード変換 adb.exe は Windowsの住人なので改行が LF でなくCRLF です。 そのため WSL側から実行してパイプに渡したりすると意図しない挙動をすることがあります。 たとえば adb devices の結果から末尾の空行を削除しようと下記のように trをつけても削除されません。 5行目に空行が入ったままですね。\n1 2 3 4 5 6 $ adb.exe devices | tr -s \u0026#34;\\n\u0026#34; List of devices attached HOGEHOGE01 device HOGEHOGE02 device $ そこで文字コード変換するために nkf を導入します。 Ubuntuの場合は aptでインストールできます。\n1 sudo apt install nkf 下記のように nkf をパイプでつなげれば改行文字をCRLF → LFにできます。 オプション -Lu が改行をLFにするオプションです。ちなみに -w はUTF8への変換です。\n1 2 3 4 5 $ adb.exe devices | nkf -Lu -w | tr -s \u0026#34;\\n\u0026#34; List of devices attached HOGEHOGE01 device HOGEHOGE02 device $ 環境変数の共有 WSLENV 下記の例のように複数のデバイスが接続されている場合、任意の１つを指定する必要があります。\n1 2 3 4 $ adb.exe devices List of devices attached HOGEHOGE01 device HOGEHOGE02 device 指定しないと下記のように、複数のデバイスがあると怒られてしまいます。\n1 2 $ adb.exe shell whoami adb.exe: more than one device/emulator デバイス指定の１つの方法として -sオプションでシリアルを指定する方法があります。\n1 2 $ adb.exe -s HOGEHOGE01 shell whoami root これでもいいのですが毎回 -s をつけるのは面倒です。 adb のヘルプを見ると下記の環境変数があると説明があります。\n$ANDROID_SERIAL serial number to connect to (see -s)\nですが下記のようにしてもうまくいきません。\n1 2 $ ANDROID_SERIAL=HOGEHOGE01 adb.exe shell whoami adb.exe: more than one device/emulator これは adb.exe がWindowsの住人なので WSL の環境変数の効果がないためです。 こで下記のように WSLENVも設定します。 WSLENVを設定するとその設定が Windows側にも環境変数が共有され 期待通り動作します。\n1 2 3 4 $ export WSLENV=ANDROID_SERIAL:HOGEHOGE01 $ export ANDROID_SERIAL=HOGEHOGE01 $ adb.exe shell whoami root WSLENV の詳細は WSLENV を使用して Windows と WSL の間で環境変数を共有するを参照してください。\nPATH形式変換 wslpath Windowsの.exeに引数を渡すときはパスの形式に注意が必要です。 WSL 側では /mnt/c/Programs/platform-tools/ という表記の場合、 Windows側ではC:\\Programs\\platform-tools\\ となります。 なのでWindowsの住人であるadb.exeに、下記のようなWSL（というかUNIX/Linux）のパス形式で渡すとエラーになります。\n1 adb.exe push /mnt/c/User/username/Download/hoge.bin /data/ これを解決するのが wslpath です。 例えば下記のように-w オプションで渡すとWindows形式に変換してくれます。\n1 2 $ wslpath -w /mnt/c/User/username/Download C:\\Users\\username\\Downloads これを利用して下記のようにすると正しく adb.exe が hoge.binのパスを認識してくれます。\n1 adb.exe push $( wslpath -w /mnt/c/User/username/Download/hoge.bin ) /data/ WSL と Ubuntuの共存 ここまでくると普通のLinuxとWSLとで同じスクリプトを共有したいという要望が出てくるかもしれません。 下記にその例を書いておきます。uname -r microsoft が含まれればWSL、なければ普通のLinuxです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # adb パス設定 if { which adb || which adb.exe } \u0026gt; /dev/null ; then ADB=$(which adb || which adb.exe) fi # WSLの環境変数をWindowsに共有する設定 ANDROID_SERIAL=\u0026#39;hogehoge\u0026#39; export WSLENV=ANDROID_SERIAL:${ANDROID_SERIAL} export ANDROID_SERIAL=${ANDROID_SERIAL} # WSL のときだけWindows形式にパス変換 # WSL は uname -r が 5.15.153.1-microsoft-standard-WSL2のように microsoft が含まれる DATA=/mnt/c/User/username/Download/hoge.bin ${ADB} push $( [[ \u0026#34;$(uname -r)\u0026#34; == *microsoft* ]] \u0026amp;\u0026amp; wslpath -w \u0026#34;${DATA}\u0026#34; || echo \u0026#34;${DATA}\u0026#34;) /data/ まとめ 今回は adb を例に、 WSLからWindowsネイティブの.exeを使う方法を説明しました。\n改行コードに注意する WSLENVで環境変数を共有 uname -r にmicrosoftが含まれればWSL、なければ普通のLinux というのを覚えておいてください！\n","permalink":"https://nagayasu-shinya.github.io/posts/wsl-windows-native-exe/","summary":"\u003cp\u003eWSLで大抵のことは完結できるようになってきましたが、ときどきWindows側の.exeを使いたくなるときがあります。\nその方法を説明します。\u003c/p\u003e","title":"WSL で Windowsネイティブな.exeを実行する"},{"content":"JSTQBというソフトウェアテストの資格をとったので、勉強法とかをメモしておきます。 サンプル問題がJSTQBのサイトにあまりなく、ISTQBのほうを参照したほうがいいです。\nJSTQB認定試験とは ソフトウェアテストの資格です。テストチームや品証のかたに特に有用かなと思います。 求人票にもときどきJSTQB保持者を優遇するところもあります。 いくつかのレベル（難易度）があるのですが、今回は一番かんたんなFoundation Levelについて述べます。 JSTQBについての説明はこの JSTQB認定テスト技術者資格とは？各コースの合格難易度と費用・勉強方法 が詳しいです。\nちなみにその上のレベルの Advanced Level は実務経験の申請が必要だそうです。 もしFoundation Levelの次に受けようと思っている方は JSTQB Advanced Level テストアナリスト(AL TA)試験とは？試験内容や学習方法 を参考にするといいかもしれません。\n勉強法 ざっとググった感じ、勉強法としては「シラバス読め」ばっかだったので、もうちょっと書いておきます。 とくにサンプル問題は意外に見落とされがちなので注意してください。 ほとんどのサイトにはサンプル問題については書かれてなかったですが、これがないとちょっと大変です。\nシラバス 公式解説書みたいなものがFLシラバスです。 ここから問題が出ます。PDFで80ページくらいです。大した量ではないですね。 何かわからないことがあったらこれで確認してください。極端な話これを暗記できれば合格できます。\nテス友 JSTQB用の勉強アプリにテス友があります。実際の試験問題よりは少し易しい問題が勉強できます。 これが8割は確実の取れるようになっておかないと危ないと思います。 間違えたとこは該当するシラバスの章を確認して暗記します。\n変な問題（日本語が意味わからんとか）が多いですがそれはご愛嬌ですね。問題文を忖度してなんとか理解してください。\nサンプル試験問題3回分 「過去問はないのか」と思う方も多いでしょうが、過去問はありません。 またJSTQBはFLサンプル問題を数問しか提供してくれていません。\nでも大丈夫です。JSTQBの親分的なISTQB（JSTQBがISTQBの日本支店みたいな感じ？）が実際の試験と同じようなサンプル問題＆解説を3回分提供していくれています。 Certified Tester Foundation Level (CTFL) v4.0のサイトの、 右の「Download Materials」というところから試験問題サンプルと回答のPDFがダウンロードできます。\nISTQBなんで日本語ではなく英語ですが、AIなんかで訳せば問題ないと思います。そんなに難しい英語ではないです。 間違えたところは回答の解説を読んでください。割と親切に、なぜこの選択肢が間違いなのかなどを説明してあります。 これは全部理解しておいたほうがいいです。実際の試験もだいたいこんな感じです（実際は日本語なのでちょっとかんたんに感じるかと）\n参考書 紙の参考書もいくつかありますが、なくても大丈夫でしょう。あってもなくてもお好みで。\nまとめ ISTQBのサンプル問題がとけるようになるまでシラバスを読んでおけば大丈夫だと思います。テス友はすくなくとも8割は答えられるようになっておく必要があります。 実際の試験の合格率は6割くらいだそうなので、自信を持って試験に望んでください。\n","permalink":"https://nagayasu-shinya.github.io/posts/jstqb-certification-study-guide/","summary":"\u003cp\u003eJSTQBというソフトウェアテストの資格をとったので、勉強法とかをメモしておきます。\nサンプル問題がJSTQBのサイトにあまりなく、ISTQBのほうを参照したほうがいいです。\u003c/p\u003e","title":"JSTQB Foundation Level 勉強法メモ"},{"content":"Jenkinsfile からコマンドを sudo で実行させたいときがあります。 そういうときの対処法を askpass をはじめ数パターンまとめてみました。\nユーザjenkinsの設定 まずはそもそもユーザ jenkins がsudoできるように設定が必要です。 下記のコマンドでまずユーザjenkins のパスワードを設定します。 パスワードは任意のパスワードでOKです。\n1 sudo passwd jenkins つぎに jenkins を sudo できるグループに追加します。Ubuntuのときは下記でOKです。 他のディストリビューションについてはググってみてください。\n1 sudo usermod -aG sudo jenkins ここまで来たら jenkins で sudo できるはずです。下記のように jenkinsにスイッチして whoami してみてください。 root と返ってくるはずです。\n1 2 3 4 $ su jenkins $ sudo whoami root $ exit ここまでは下記のどの方法をするにしても必要な作業です。\nパスワード無しでsudoできるようにする 1つ目の方法は、ユーザ jenkins でパスワードなしでsudoできるようにしてしまう方法です。 乱暴すぎるのであまりおすすめはしませんが、まずは紹介します。 sudo の設定を変更する下記のコマンドを実行します。\n1 sudo visudo すべてのコマンドをパスワード無しで実行するには下記のように記述します。\n1 2 Defaults:jenkins !requiretty jenkins ALL=(ALL) NOPASSWD:ALL 全部のコマンドは必要ない場合は必要なコマンドだけパスワードなしにもできます。 下記の例ではコマンド /path/to/command だけパスワードなしにする設定です。 詳細は「sudoers NOPASSWD」でググるといろいろ出てきます。\n1 2 Defaults:jenkins !requiretty jenkins ALL=(ALL) NOPASSWD: /path/to/command expectコマンドを使う 対話的コマンドを自動化するツールにexpectがあります。 対話的なコマンドを自動化できるすぐれものです。ベースがTclなので結構とっつきにくいです。\nJenkinsfile にかくときはシェバンを /usr/bin/expect にすればOKです。下記の例はsudoするときの例です。 spawnがプロセス実行、expectがコマンドからのレス待ち、sendがコマンドへの入力です。 下記のコードを見ればなんとなくわかるかと思います。 最後のexpectはプロンプトの\\$が表示されるのを待っています。\n1 2 3 4 5 6 7 8 withCredentials([usernamePassword(credentialsId: \u0026#39;user_jenkins\u0026#39;, passwordVariable: \u0026#39;jenkins_password\u0026#39;, usernameVariable: \u0026#39;jenkins_username\u0026#39;)]) { sh \u0026#34;\u0026#34;\u0026#34;\\ |#!/usr/bin/expect -f |spawn sudo bash -c \\\u0026#34;rm -rf *\\\u0026#34; |expect -re \u0026#34;password for $jenkins_username\u0026#34; |send -- \u0026#34;$jenkins_password\\\\r\u0026#34; |expect \u0026#34;\\$\u0026#34; \u0026#34;\u0026#34;\u0026#34;.stripMargin()} askpassを使う これが一番おすすめです。 askpassについてはなんかかきたい - askpassのことを書いておくに紹介記事がありました。 パスワードを標準出力に吐くスクリプトを作って、環境変数SUDO_ASKPASS　にそのスクリプトのパスを設定すればOKです。 sudo するときに -A をつけます。\nJenkinsfile の例 Jenkinsで書くと下記のようになります。 パスワードを吐くスクリプトをワークスペースにおいてしまうと、ブラウザからアクセスできてしまうのでWORKSPACE_TMP を利用します。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 withCredentials([usernamePassword(credentialsId: \u0026#39;user_jenkins\u0026#39;, passwordVariable: \u0026#39;jenkins_password\u0026#39;, usernameVariable: \u0026#39;jenkins_username\u0026#39;)]) { script { // パスワードを標準出力に吐き出すスクリプト作成 // sudo には -A オプションが必要 // WORKSPACEの下にスクリプトを置くと、そのスクリプトをブラウザから参照できてしまうので // WORKSPACE_TMP を利用している sh \u0026#34;mkdir -p $env.WORKSPACE_TMP\u0026#34; String sudoAskpass = sh(returnStdout: true, returnStatus: false, script: \u0026#34;mktemp --tmpdir=${env.WORKSPACE_TMP}/ ${BUILD_TAG}.XXXXXXXXXX\u0026#34;).trim() sh \u0026#34;\u0026#34;\u0026#34;\\ |#!/bin/bash -eu |echo -e \u0026#39;#!/bin/bash\\\\necho $jenkins_password\u0026#39; \u0026gt; $sudoAskpass |chmod u+x $sudoAskpass |export SUDO_ASKPASS=$sudoAskpass |sudo -A whoami |\u0026#34;\u0026#34;\u0026#34;.stripMargin() // もう一度sudoを使うにはexportが必要 sh \u0026#34;\u0026#34;\u0026#34;\\ |#!/bin/bash -eu |export SUDO_ASKPASS=$sudoAskpass |sudo -A whoami |\u0026#34;\u0026#34;\u0026#34;.stripMargin() } } まとめ Jenkinsfile から sudo する方法を説明しました。expect か askpass を使うのがいいかなと思います！\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-sudo-configuration/","summary":"\u003cp\u003e\u003ccode\u003eJenkinsfile\u003c/code\u003e からコマンドを \u003ccode\u003esudo\u003c/code\u003e で実行させたいときがあります。\nそういうときの対処法を \u003ccode\u003easkpass\u003c/code\u003e をはじめ数パターンまとめてみました。\u003c/p\u003e","title":"Jenkinsfile で sudo する方法"},{"content":"Jenkinsのジョブ実行時に、ジョブにファイルを渡すことができます。 デフォルトの機能なんですがうまく動作せず、プラグインを導入して解決できました。 ちょっとクセがあるのでその使い方を説明します。\nデフォルトのファイルアップロード機能 デフォルトのビルドパラメータにファイルをアップロードするための設定項目があります。 ジョブ設定の中の、文字列や真偽値を渡す設定のできる「ビルドのパラメーター」のところにファイルアップロードの設定もあります。 これを設定するとジョブ実行時にファイルをアップロードしてジョブに渡すことができるはずです。\nそこで Declarative Directive Generator で生成したコード片を参考に下記のようなコードで試したところ、悲しいことに動作しませんでした。\n1 2 3 parameters { file name: \u0026#39;UPLOADFILE\u0026#39;, description: \u0026#39;ジョブ実行時にアップロードするファイル\u0026#39; } File Parameterプラグイン いろいろググってみたところFile Parameterというプラグインを見つけました。 そのプラグインの説明で\nOffers alternative types of file parameter that are compatible with Pipeline and do not suffer from the architectural flaws of the type built into Jenkins core.\nとあるので、ファイルアップロードできないのはまあよくある問題のようです。\nいろいろ試したところ、上記のプラグインでファイルのアップロードできました。ただちょっとクセがあるので使い方を下記に書きます。\nFile Parameterプラグイン有効化 このプラグインをインストールすると、ジョブ設定の「ビルドのパラメーター」のところにデフォルトのファイルアップロードに似た設定が追加されます。 Stashed File Parameter というのがそれです。\nJenkinsfile で書くと下記のようになります。\n1 2 3 4 parameters { /* file パラメータはどうもpipelineでは動作しないらしいのでプラグインを利用. */ stashedFile name: \u0026#39;UPLOADFILE\u0026#39;, description: \u0026#39;ジョブ実行時にアップロードするファイル\u0026#39; } これでワークスペースにジョブ開始時にアップロードしたファイルが、 ワークスペースに UPLOADFILE というファイル名で保存されます。 ワークスペース上のファイル名は、オリジナルのファイル名に関わらず上記のparameter のとこで指定した名前になります。\nファイル名をオリジナルと同じにする アップロードされたファイル名が毎回固定のファイル名に変換されてしまうのは嫌な場合も多いかと思います。 そこでファイル名をオリジナルに戻す方法を２つ説明します。\nまずは withFileParameter() を利用する方法です。 このメソッドの説明は公式サイトのFile Parameter Pluginにあり、 さらにその利用方法がプラグインの help.htmlにあります。 抜粋すると下記のようになります。この場合 $UPLOADFILE がオリジナルのファイル名です。 注意が必要なのはこれはGroovyの変数ではありません。ですのでJenkinsfileから直接展開はできません。\n下記の例ではシングルクォートでそのまま $UPLOADFILE としてシェルに渡しています。 もしダブルクォーテーションをつかうなら \\$UPLOADFILE のようにエスケープが必要です。\n1 2 3 4 5 6 7 8 9 10 11 stages { stage (\u0026#39;アップロードファイルのリネーム\u0026#39;) { steps { script { withFileParameter(name:\u0026#39;UPLOADFILE\u0026#39;, allowNoFile: true) { sh \u0026#39;if [ -f \u0026#34;$UPLOADFILE\u0026#34; ]; then mv UPLOADFILE $UPLOADFILE; fi\u0026#39; } } } } } ファイル名をオリジナルと同じにする（別の方法） 上記の方法でもOKですが、いちいち withFileParameter() で囲むのがめんどくさい場合は下記のようにできます。 下記の例ではファイルをアップロードしなかった場合も判定しています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 stages { stage (\u0026#39;アップロードファイルのリネーム\u0026#39;) { steps { script { if (sh(returnStdout: false, returnStatus: true, script: \u0026#39;test -n \u0026#34;$UPLOADFILE_FILENAME\u0026#34;\u0026#39;) == 0) { unstash \u0026#39;UPLOADFILE\u0026#39; sh \u0026#34;mv UPLOADFILE \\$UPLOADFILE_FILENAME\u0026#34; // エスケープ必要. } else { echo \u0026#34;UPLOADFILE is not uploaded.\u0026#34; } } } } } まず、*_FILENAME でアップロードしたファイルのファイル名を取得できます。 上記の例では UPLOADFILE_FILENAME がそれに該当します。 このファイル名が空かどうかでファイルがアップロードされたのか判定しています。 test -n \u0026quot;$UPLOADFILE_FILENAME\u0026quot; の部分です。 この変数もGroovyの変数ではないのでシングルクォートで囲むかエスケープしてください。 次に unstash でファイルを実際に取得します。ここで初めてワークスペースにファイルがコピーされます。 あとは mv でファイル名前を変更すれば、ワークスペースにもとのファイル名でファイルがアップロードされたことになります。\nまとめ 今回はJenkinsでファイルをアップロードするプラグインの使い方を説明しました。 ちょっとクセがあるのでこの記事を参考にいろいろ試してみてください。\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-file-parameter-plugin/","summary":"\u003cp\u003eJenkinsのジョブ実行時に、ジョブにファイルを渡すことができます。\nデフォルトの機能なんですがうまく動作せず、プラグインを導入して解決できました。\nちょっとクセがあるのでその使い方を説明します。\u003c/p\u003e","title":"Jenkins でジョブにファイルをアップロードするプラグイン"},{"content":"PetaLinux SDカードイメージの未使用領域を削減して、バックアップ時のイメージサイズを最適化する方法を説明します。\nXilinx の FPGA ボードではYocto LinuxをベースにしたPetaLinuxが採用されています。 このLinuxを使用するためにはRaspberry Piと同じようにSDカードにイメージを書き込んで、そのSDカードを基板に挿して使用します。\nイメージは2つのパーティションからなります。 1つ目はFATでフォーマットされたブートローダなどが格納されるパーティションで、 もう1つはext4でフォーマットされたルートファイルシステムのパーティションです。 これは下記のマクニカ社のWIC 形式の SD カードイメージの扱い方のページがわかりやすいです。\n通常利用するときには、ルートファイルシステムはSDカードの容量を最大限まで使えるようにしておけば良いですが、 SDカードのイメージをまるごとバックアップしようとした場合に、使用していない領域までバックアップを取るのは時間がかかってしまいます。 そこで今回は未使用領域部分を削減してルートファイルシステムのパーティションのサイズを小さくします。 また、小さくしたあとで最大サイズに戻す方法も説明します。 試してはいませんがおそらくRaspberry Piでも同じ手順で行けると思います。\nイメージの容量を削減する まずPetaLinuxのイメージサイズを削減する方法を説明します。\nホストマシンでSDカードを認識させる 動作している基板上でパーティションサイズを小さくさせることはできないので、別のマシンにて作業します。ここではUbuntu22.04を使用します。Linuxならたいてい使えると思います。 今回の例では下記のように/dev/sdbがSDカードに割り当てられました。 パーティションsdb1 はFATのブートローダなど、sdb2はext4のルートファイルシステムです。 64GBのSDカードで最大限までルートファイルシステムのパーティションを広げている状態です。\n1 2 3 4 5 $ sudo fdisk -l （略） デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ /dev/sdb1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/sdb2 4194312 124735487 120541176 57.5G 83 Linux 現状のパーティション情報を確認する sdb2がPetaLinuxのルートファイルシステムだとわかったので、次にファイルシステムの最小サイズを調べます。 コマンドresize2fsに大文字のPをオプションとして渡せば最小サイズを表示してくれます。 ここで注意ですが、表示されるのはByte数でなくブロック数です。下記の例では3199265ブロックとなります。\n1 2 3 4 $ umount /dev/sdb2 $ sudo resize2fs -P /dev/sdb2 resize2fs 1.46.5 (30-Dec-2021) Estimated minimum size of the filesystem: 3199265 ブロックサイズは下記のコマンドで確認できます。4KBですね。\n1 2 $ sudo /sbin/tune2fs -l /dev/sdb2 | grep \u0026#39;Block size\u0026#39; Block size: 4096 パーティションサイズを小さくする まずはじめにファイルシステムのチェックから行います。これを先に実行しないとパーティション変更時にコマンドがはじかれます。\n1 sudo e2fsck -p -f /dev/sdb2 先程調べたブロック数とブロックサイズは3199264 × 4KBで、これはおよそ12.5GBなので、ここでは少し大きめの13GBにしておきます。サイズ変更のオプションは小文字のpです。\n1 sudo resize2fs -p /dev/sdb2 13G これでファイルシステムを13GBに縮小できました。\nパーティションサイズの縮小 ファイルシステムは縮小できましたが、まだ肝心のパーティションを縮小していません。パーティション縮小にはfdiskを使います。対話的コマンドです。 まず最初にFAT側のパーティションもアンマウントします（こっちは変更しません）。\n1 umount /dev/sdb2 いよいよパーティションを修正します。対話的コマンドなので、入力するところで「★」をつけて説明を入れておきます。 やることはext4パーティションをいったん削除して、再度作り直してパーティションサイズを再設定することです。このときパーティションサイズは、さっき行ったファイルシステムのサイズ変更で指定したサイズより大きくする必要があります（パーティションサイズ＞ファイルシステムサイズにする）。ここでは13GBより大きい14GBにしています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 $ sudo fdisk /dev/sdb fdisk (util-linux 2.37.2) へようこそ。 ここで設定した内容は、書き込みコマンドを実行するまでメモリのみに保持されます。 書き込みコマンドを使用する際は、注意して実行してください。 コマンド (m でヘルプ): m　★ ヘルプを表示 ヘルプ: DOS (MBR) a 起動可能フラグを切り替えます b 入れ子の BSD ディスクラベルを編集します c DOS 互換フラグを切り替えます 一般 d パーティションを削除します F パーティションのない領域を一覧表示します l 既知のパーティションタイプを一覧表示します n 新しいパーティションを追加します p パーティション情報を表示します t パーティションタイプを変更します v パーティション情報を検証します i パーティションの情報を表示します その他 m このメニューを表示します u 表示項目の単位を変更します x 特殊機能に移動します (熟練者向け機能) スクリプト I ディスクのレイアウトを sfdisk 互換のスクリプトから読み込みます O ディスクのレイアウトを sfdisk 互換のスクリプトに書き出します 保存と終了 w パーティション情報をディスクに書き込んで終了します q 変更点を保存せずに終了します 新しいラベルを作成します g 新しい (何もない) GPT パーティションテーブルを作成します G 新しい (何もない) SGI (IRIX) パーティションテーブルを作成します o 新しい (何もない) DOS パーティションテーブルを作成します s 新しい (何もない) Sun パーティションテーブルを作成します コマンド (m でヘルプ): p ★ いまのパーティション情報を確認。sdb2の開始位置を覚えておくこと！ ディスク /dev/sdb: 59.48 GiB, 63864569856 バイト, 124735488 セクタ Disk model: SD/MMC 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x07e7b6bb デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ /dev/sdb1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/sdb2 4194312 124735487 120541176 57.5G 83 Linux コマンド (m でヘルプ): d ★パーティション削除 パーティション番号 (1,2, 既定値 2): 2　★間違ってFATのほうの１を消さないように。 パーティション 2 を削除しました。 コマンド (m でヘルプ): p ★ extのほうのパーティションが消えているか確認する ディスク /dev/sdb: 59.48 GiB, 63864569856 バイト, 124735488 セクタ Disk model: SD/MMC 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x07e7b6bb デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ /dev/sdb1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) コマンド (m でヘルプ): n ★ 消したパーティションを再作成 パーティションタイプ p 基本パーティション (1 primary, 0 extended, 3 free) e 拡張領域 (論理パーティションが入ります) 選択 (既定値 p): p ★ プライマリでOK パーティション番号 (2-4, 既定値 2): 2　★　消した方のパーティション番号を指定 最初のセクタ (4194312-124735487, 既定値 4196352): 4194312 ★さっき控えておいた開始位置を入力する Last sector, +/-sectors or +/-size{K,M,G,T,P} (4194312-124735487, 既定値 124735487): +14G ★プラスに続けて確保したいサイズを入力する 新しいパーティション 2 をタイプ Linux、サイズ 14 GiB で作成しました。 パーティション #2 には ext4 署名が書き込まれています。 署名を削除しますか？ [Y]es/[N]o: N ★変更する必要ないのでNoにする コマンド (m でヘルプ): w　★　このw入力したら初めて変更が反映される、言い換えればここでwを入力しなければ何も変更されない パーティション情報が変更されました。 ioctl() を呼び出してパーティション情報を再読み込みします。 ディスクを同期しています。 これでパーティションサイズを14GBに減らせました。\n動作確認 パーティションサイズの確認 念のため実機でパーティション情報を確認しておきます。さきほどのSDカードを基板に挿してLinuxを起動させます。そして基板上で df でファイルシステムを確認します、期待通り13GBだけ見えています。\n1 2 3 4 5 6 7 8 9 10 11 $ df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 1.5G 4.0K 1.5G 1% /dev /dev/mmcblk1p2 13G 12G 690M 95% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 787M 18M 769M 3% /run tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup tmpfs 2.0G 0 2.0G 0% /tmp tmpfs 2.0G 204K 2.0G 1% /var/volatile /dev/mmcblk1p1 2.0G 44M 2.0G 3% /boot tmpfs 394M 0 394M 0% /run/user/0 つぎにパーティション情報を確認します。期待通り14GBになっていますね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ sudo fdisk -l 略 Disk /dev/mmcblk1: 59.48 GiB, 63864569856 bytes, 124735488 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x07e7b6bb Device Boot Start End Sectors Size Id Type /dev/mmcblk1p1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/mmcblk1p2 4194312 33554431 29360120 14G 83 Linux パーティションサイズ削減したイメージのバックアップ SDカードのLinuxイメージをバックアップするときは下記のようにddコマンドで抽出します。\n1 sudo dd if=/dev/sdb of=petalinux.bin bs=1M status=progress しかしこれだとSDカード全体を読み込むので、サイズ削減した意味がないです。どこまで読み込むかを指定する必要があります。 どこまで読み込めばいいかは、fdisk の情報から計算できます。下記のように表示された場合、データの末尾は 29360120セクターです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ sudo fdisk -l 略 ディスク /dev/sdb: 59.48 GiB, 63864569856 バイト, 124735488 セクタ Disk model: SD/MMC 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x07e7b6bb デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ /dev/sdb1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/sdb2 4194312 33554431 29360120 14G 83 Linux 1セクタは512Byteなので、 29,360,120 * 512 = 15,032,381,440 Byte ≒ 14,336 MByte です。 dd の bs オプションに 1MBを指定しているので結局この場合は下記のように指定すればOKです。\n1 sudo dd if=/dev/sdb of=petalinux-14GB.bin bs=1M count=14336 status=progress ループバックデバイスにマウントして確認 上記で取得したバックアップイメージの確認をしておきましょう。一番確実なのはSDカードにイメージを書き込んで起動させてみることです。 SDカードに書くときはcountは要らないですね、ファイルサイズ末尾まで書き込めばいいので。\n1 sudo dd of=/dev/sdb if=petalinux-14GB.bin bs=1M status=progress ただこれは結構時間がかかるかと思うので、別の方法でやってみます。 ループバックデバイスにマウントしてみるのが手っ取り早いかと思います。ループバックデバイスを使うことで下記のようにイメージファイルをそのままマウントできます。 オプションにloopをつけ、offsetオプションにパーティションの開始位置を指定します。マウントできたらルートファイルシステムの中のファイルが見れるはずです。\n1 2 3 4 $ sudo mkdir /media/shinya/petalinux-14GB/ $ sudo mount -o loop,offset=$((512 * 4194312)) ./petalinux-14GB.bin /media/shinya/petalinux-14GB/ $ ls /media/shinya/petalinux-14GB/ bin boot configfs dev etc home lib lost+found media mnt proc run sbin srv sys tmp usr var パーティションサイズを大きくする さきほどはパーティションサイズを小さくしましたが、実際に基板を動かすときはパーティションサイズをSDカード容量いっぱいまで大きくしたいこともあるかと思います。 パーティションを大きくするには、小さくすときと違って、基板上のLinuxでそのまま実行できます。\nXilinx は resize-partというコマンド（シェルスクリプト）を用意してくれているのでそれを使えば一発です。 fdiskでデバイスファイルを確認して、それを引数に渡すだけです。これでSDカード上限までサイズが拡大されます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # fdisk -l 略 Disk /dev/mmcblk1: 59.48 GiB, 63864569856 bytes, 124735488 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x07e7b6bb Device Boot Start End Sectors Size Id Type /dev/mmcblk1p1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/mmcblk1p2 4194312 33554431 29360120 14G 83 Linux # resize-part /dev/mmcblk1p2 # reboot もし resize-part がなければ手動で下記のように実行すればOKです。\n1 2 3 4 5 6 $ sudo bash -c \u0026#39;echo -e \u0026#34;Yes\u0026#34; | parted /dev/mmcblk1 ---pretend-input-tty resizepart 2 100%\u0026#39; Warning: Partition /dev/mmcblk1p2 is being used. Are you sure you want to continue? Yes/No? Yes Information: You may need to update /etc/fstab. $ sudo resize2fs /dev/mmcblk1p2 $ reboot 再起動後に下記のようにパーティションとファイルシステムサイズが最大化されているはずです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 $ sudo fdisk -l 略 Disk /dev/mmcblk1: 59.48 GiB, 63864569856 bytes, 124735488 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x07e7b6bb Device Boot Start End Sectors Size Id Type /dev/mmcblk1p1 * 8 4194311 4194304 2G c W95 FAT32 (LBA) /dev/mmcblk1p2 4194312 124735487 120541176 57.5G 83 Linux $ df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 1.5G 4.0K 1.5G 1% /dev /dev/mmcblk1p2 57G 13G 42G 24% / tmpfs 2.0G 0 2.0G 0% /dev/shm tmpfs 787M 10M 777M 2% /run tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup tmpfs 2.0G 0 2.0G 0% /tmp tmpfs 2.0G 200K 2.0G 1% /var/volatile /dev/mmcblk1p1 2.0G 44M 2.0G 3% /boot tmpfs 394M 0 394M 0% /run/user/0 まとめ 今回はPetaLinuxのSDカード内のイメージのサイズを削減する方法を説明しました。また、動作確認を簡単にするためループバックマウントの方法も説明しました。さらに、パーティションサイズを最大解する方法も説明しました。 SDカードをまるっとバックアップするのは結構時間がかかるので、これらの方法を利用してみてください。\n","permalink":"https://nagayasu-shinya.github.io/posts/linux-image-size-optimization/","summary":"\u003cp\u003ePetaLinux SDカードイメージの未使用領域を削減して、バックアップ時のイメージサイズを最適化する方法を説明します。\u003c/p\u003e","title":"PetaLinux のイメージサイズ削減＆パーティションサイズ最大化"},{"content":"ssh で接続するとき、鍵は変更していないのにPermission denied (publickey) というエラーがでることがあります。 ここではOpenSSH のバージョンが新しくなったことが原因の場合の解決法を説明します。\n今回扱う発生条件 SSH 接続エラーはいろんな原因で発生しますが、今回は OpenSSHのバージョンを新しく更新したときの解決法を説明します。 具体的にはバージョン8.8 以降に新しくした場合について説明します。 これはたとえば Ubuntu を Ubuntu18.04（OpenSSH 7.6p1）から Ubuntu20.04（OpenSSH 8.9p1）にバージョンアップした場合に起こります。\nコマンド例 今回は例として git clone を ssh 接続した場合を例に説明します。 例えば下記のようにエラーが発生したとします。ユーザー名やサーバは架空のものです。 Permission denied (publickey).といわれていますね。\n1 2 3 4 5 6 7 $ git clone ssh://shinya@hogehoge.com/sample.git Cloning into \u0026#39;sample\u0026#39;... shinya@sample.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. ssh のデバッグ情報を出力 .ssh ディレクトリ以下の鍵ファイルのパーミッションや .ssh/config におかしなところがないかを確認して、問題がなさそうなら ssh をデバッグ情報つきで実行します。 -vT オプションでOKでしょう。すると下記のようにたくさんの情報が出力されます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ ssh -vT shinya@hogehoge.com OpenSSH_8.9p1 Ubuntu-3ubuntu0.1, OpenSSL 3.0.2 15 Mar 2022 debug1: Reading configuration data /home/shinya/.ssh/config debug1: /home/shinya/.ssh/config line 1: Applying options for hogehoge.com debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * 略 debug1: send_pubkey_test: no mutual signature algorithm debug1: No more authentication methods to try. shinya@hogehoge.com: Permission denied (publickey). この最後の方にエラーの原因が書いてあるはずです。今回の例では debug1: send_pubkey_test: no mutual signature algorithm と怒られています。 なにやらアルゴリズムがだめそうです。\nエラーの原因 ssh-keygen で鍵を作成する場合、デフォルトで RSA 暗号化形式で作成されてます。 しかしこの暗号アルゴリズム RSA が脆弱性のため非推奨になったため、 OpenSSH 8.8 以降から RSA を受け付けないようになっているようです。 このため OpenSSH のバージョンが新しくなると上述のエラーが発生してしまいます。 もしつかっている鍵のアルゴリズムがよくわからなければ下記のようにssh-keygen で確認できます。\n1 2 $ ssh-keygen -l -f ~/.ssh/hoge_key.pub 2048 SHA256:8woLDZ0ab+nyIR4jvoGiHb+LEtaQw2/uwIf5zhz1BVw shinya@sample.com (RSA) 回避方法 正しい解決方法はRSAでなくもっと強度の強い暗号アルゴリズムで鍵を再作成することです。しかしいろんな事情からそれができない場合もあるかと思います。 そこでひとまずRSA のままでSSHを動かすワークアラウンドの方法を書いておきます。\n.ssh/config の修正 .ssh/config に RSA を使用するように HostKeyAlgorithms と PubkeyAcceptedKeyTypes を下記のように追記します。 これで hogehoge.com に接続するときは RSA が使えるようになります。\n1 2 3 4 $ vim .ssh/config Host hogehoge.com HostKeyAlgorithms +ssh-rsa PubkeyAcceptedKeyTypes +ssh-rsa 複数のサーバに対して RSAを使えるようにした場合は、同様に上記2つの設定を追加してください。\n接続確認 再度 ssh を実行して接続できればOKです。 もし下記のようなメッセージが表示された場合はもうちょっと作業が必要です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ ssh -vT shinya@hogehoge debug1: Reading configuration data /home/shinya/.ssh/config debug1: /home/shinya/.ssh/config line 1: Applying options for hogehoge.com debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * 略 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is SHA256:h4p/Jl86nBeejcE4WsGPleemG95dIzJigiIlcgQhyyM. Please contact your system administrator. Add correct host key in /home/shinya/.ssh/known_hosts to get rid of this message. Offending ECDSA key in /home/shinya/.ssh/known_hosts:5 remove with: ssh-keygen -f \u0026#34;/home/shinya/.ssh/known_hosts\u0026#34; -R \u0026#34;shinya@hogehoge.com\u0026#34; Host key for hogehoge.com has changed and you have requested strict checking. Host key verification failed. デバッグ情報を見てみると .ssh/known_hosts がなにやらまずいようです。この場合は Offending ECDSA key in /home/shinya/.ssh/known_hosts:5 とあるので、.ssh/known_hosts の5行目で、RSA でなく ECDSA アルゴリズムを指定してしまっているようです。 いまは RSA で接続したいので、5行目を削除してしまいましょう。 メッセージにある通り下記のコマンドで削除できます。\n1 ssh-keygen -f \u0026#34;/home/shinya/.ssh/known_hosts\u0026#34; -R \u0026#34;shinya@hogehoge.com\u0026#34; もう一度 ssh を実行してみてください。 known_hosts から削除したので途中で Are you sure you want to continue connecting と尋ねられますので yes と答えておきます。 あとは最後に Exit Status 0 と表示されれば接続成功です。 お疲れ様でした。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ ssh -vT shinya@hogehoge OpenSSH_8.9p1 Ubuntu-3ubuntu0.1, OpenSSL 3.0.2 15 Mar 2022 debug1: Reading configuration data /home/shinya/.ssh/config debug1: /home/shinya/.ssh/config line 1: Applying options for hogehoge.com debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files debug1: /etc/ssh/ssh_config line 21: Applying options for * 略 This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added \u0026#39;hogehoge.com\u0026#39; (RSA) to the list of known hosts. 略 debug1: channel 0: free: client-session, nchannels 1 Transferred: sent 2472, received 66728 bytes, in 1.0 seconds Bytes per second: sent 2599.2, received 70161.2 debug1: Exit status 0 正攻法 上記の回避方法はあくまでワークアラウンドです。強度の弱いRSAを使い続けることはセキュリティ的に好ましくありません。 もっと強度の強い暗号で鍵を再作成するのが正しい対応です。サーバへの公開鍵の登録などはやり直しになりますが。 どの暗号アルゴリズムを使うかですが、 いま時点では Ed25519 を使うのが良いようです。これなら当分は大丈夫でしょう。\n1 ssh-keygen -t ed25519 OpenSSH 8.8 リリースノート 参考までに OpenSSH 8.8 Release Note のリンクを貼っっておきます。 「Potentially-incompatible changes」というところが今回のRSAについてです。\nまとめ 今回は OpenSSH をバージョンアップした際におこるエラーの対策について説明しまいた。 ワークアラウンドでひとまず逃げる方法も書いておきました。正しくは強度の強い暗号アルゴリズムで鍵を再作成することです。ご参考になれば。\n","permalink":"https://nagayasu-shinya.github.io/posts/openssh-rsa-key-compatibility-fix/","summary":"\u003cp\u003e\u003ccode\u003essh\u003c/code\u003e で接続するとき、鍵は変更していないのに\u003ccode\u003ePermission denied (publickey)\u003c/code\u003e というエラーがでることがあります。\nここではOpenSSH のバージョンが新しくなったことが原因の場合の解決法を説明します。\u003c/p\u003e","title":"OpenSSHをバージョンアップしたら ssh 接続できなくなったときの対策"},{"content":"プロキシ環境下でSSH経由の git clone を行うための、corkscrew を使ったSSHトンネルの設定方法を説明します。\nプロキシが導入されている職場の場合、git clone できない場合があります。 HTTPS経由でよいなら下記の記事の設定で行けるようになるかと思います。 WSLのProxy設定方法 しかし sshで cloneした場合はこれではできません。 今回は Proxy 環境で ssh で git clone する方法を説明します。\nプロキシ環境下のエラー 社内プロキシの環境でcloneしようとすると下記のようにエラーになる場合があります。 サーバにアクセスできない場合です。\n1 2 3 4 5 $ git clone --verbose git://git.yoctoproject.org/poky.git Cloning into \u0026#39;poky\u0026#39;... Looking up git.yoctoproject.org ... done. Connecting to git.yoctoproject.org (port 9418) ... fatal: unable to connect to git.yoctoproject.org: git.yoctoproject.org[0: 198.145.29.90]: errno=Connection timed out corkscrew 上記の問題を解決するために Corkscrew を使います。 インストールはUbuntuなら apt でできます。\n1 sudo apt-get install corkscrew つぎにその corkscrew をラップするスクリプトを作成します。 どこでもいいのですが下記の例では ~/bin/ 以下につくっています。 proxy-host と proxy-portのところにはお使いの実際のプロキシのURL、ポートを指定してください。\n1 2 3 4 5 6 $ echo \u0026#39;#!/bin/bash\u0026#39; \u0026gt; ~/bin/git-proxy.sh $ echo \u0026#34;/usr/bin/corkscrew proxy-host proxy-port $1 $2\u0026#34; \u0026gt;\u0026gt; ~/bin/git-proxy.sh $ chmod +x ~/bin/git-proxy.sh $ cat ~/bin/git-proxy.sh #!/bin/bash /usr/bin/corkscrew proxy-host proxy-port $1 $2 あとは GIT_PROXY_COMMAND 環境変数に上記スクリプトを設定し、 PATH変数にそのスクリプトのあるディレクトリを追加します。 下記のようにbashrc に追加しておけばよいかと。\n1 2 3 4 5 6 $ echo \u0026#34;export PATH=$PATH:~/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc $ echo \u0026#34;export GIT_PROXY_COMMAND=~/bin/git-proxy.sh\u0026#34; \u0026gt;\u0026gt; ~/.bashrc $ tail ~/.bashrc -n2 export PATH=$PATH:~/bin export GIT_PROXY_COMMAND=~/bin/git-proxy.sh $ source ~/.bashrc これで git clone できるようになったはずです。\nまとめ Proxy環境でgit clone する場合にはcorkscrewを使えばOKです。 GIT_PROXY_COMMAND を設定してください。\n","permalink":"https://nagayasu-shinya.github.io/posts/git-ssh-proxy-tunnel/","summary":"\u003cp\u003eプロキシ環境下でSSH経由の \u003ccode\u003egit clone\u003c/code\u003e を行うための、\u003ccode\u003ecorkscrew\u003c/code\u003e を使ったSSHトンネルの設定方法を説明します。\u003c/p\u003e","title":"Proxy環境下でSSHでgit clone する"},{"content":"ネットワークなどの理由でサーバにアクセスできないときにGit のコミット情報を送るときに使える便利機能 git bundleについて説明します。\nGit で複数人で開発するときは、通常はサーバにリモートリポジトリを用意してみんなでそこへ git push, git pull してコードを共有すると思います。 しかしたとえば他社のかたと共同開発する場合にセキュリティの問題や契約の問題で、 リモートリポジトリを共有できないこともあると思います。 この場合に便利なgit bundle コマンドを紹介します。\nいくつかの方法 リモートリポジトリを使わずにgitでのコード差分を共有する一番素朴な方法はgit diff の出力を共有することです。 しかしこの方法はコミット時の commiter や author の情報は失われてしまいます。 あまりおすすめできません。 もう少し賢い方法は、git format-patchを使うことです。 これは下記のようにメールで転送するようなヘッダ情報を付加してくれます。 このヘッダからパッチを当てるときにauthorを生成します。 ただし１つのコミットに１つのパッチファイルとなるので数十のコミットを共有するのには向きません。\n1 2 3 4 5 6 7 8 9 From 733e90dfe942bd60e8c386b0be79093ffc72fa9a Mon Sep 17 00:00:00 2001 From: NAGAYASU Shinya Date: Thu, 26 Jan 2023 00:03:14 +0900 Subject: [PATCH 1/2] =?UTF-8?q?elisp/=20elpa/=20=E3=82=92=E7=84=A1?= =?UTF-8?q?=E8=A6=96=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit さらに賢い方法は git bundleを使うことです。これは pushした場合に転送するデータと同じものを１つのファイルにまとめてくれます。 つまり通常のgit commit git push するときと同じようなことができます。 この記事ではこの git bundle を説明します。\ngit bundle git bundle のかんたんな使い方を説明します。\nバンドルファイルの作り方 まず共有したいコードを通常通り git commit します。 ここでは下記のようにorigin/masterから１つコミットしたとします（7e6e483）。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * commit 7e6e483 (HEAD) | Author: NAGAYASU Shinya | AuthorDate: Fri Jan 27 23:15:23 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Fri Jan 27 23:15:23 2023 +0900 | | ime 追加 | * commit dad82e3 (origin/master, origin/HEAD) | Author: NAGAYASU Shinya | AuthorDate: Mon Jan 23 23:46:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Mon Jan 23 23:46:02 2023 +0900 | | いくつかの変数をダイナミックバインディングに変更 このコミットのバンドルファイルを作成します。 下記のコマンドでHEADからmasterまで、つまり最新のコミットをバンドル化できます。\n1 git bundle create dot_emacs_20230127.bundle HEAD master この作成したファイル dot_emacs_20230127.bundle をコードを共有したい人に何かしらの方法で送ります。 これでバンドルの作成は終わりです。\nバンドルファイルの適用の仕方 受け取ったひとのコミットが下記のようになっていたとします。 バンドルをつくったひとより３つコミットが進んだ状態です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 * commit 733e90d (HEAD -\u0026gt; master, origin/master, origin/HEAD) | Author: NAGAYASU Shinya | AuthorDate: Thu Jan 26 00:03:14 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Thu Jan 26 00:03:14 2023 +0900 | | elisp/ elpa/ を無視しないように修正 | * commit d96b8b2 | Author: NAGAYASU Shinya | AuthorDate: Wed Jan 25 23:45:14 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Wed Jan 25 23:52:03 2023 +0900 | | C-h をバックスペースに変更 | * commit 7fb8ef8 | Author: NAGAYASU Shinya | AuthorDate: Tue Jan 24 23:27:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Tue Jan 24 23:27:02 2023 +0900 | | magit を追加してみた | * commit dad82e3 | Author: NAGAYASU Shinya | AuthorDate: Mon Jan 23 23:46:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Mon Jan 23 23:46:02 2023 +0900 | | いくつかの変数をダイナミックバインディングに変更 | まず、受け取ったバンドルファイルを適用できるかを git bundle verifyで確認します。 下記のように okay と表示されれば大丈夫です。\n1 2 3 4 5 6 $ git bundle verify ./dot_emacs_20230127.bundle The bundle contains these 2 refs: d62f68eb5a2b7cf036355aa8f1a16c9af35b8499 HEAD d62f68eb5a2b7cf036355aa8f1a16c9af35b8499 refs/heads/master The bundle records a complete history. ./dot_emacs_20230127.bundle is okay git fetch でバンドルを取り込みます。 下記のようにFETCH_HEADが更新されます。\n1 2 3 $ git fetch ./dot_emacs_20230127.bundle From ./dot_emacs_20230127.bundle * branch HEAD -\u0026gt; FETCH_HEAD git log でFETCH_HEAD を確認します。 期待通りコミットが入ったのが確認できます。 ただしバンドル作成時と受取時でコミットの状態が異なったので枝分かれてしまっています。 merge してもいいのですが、ここではログが１本線になるようにrebaseをしてみます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 $ git log --graph --decorate --pretty=fuller --all --abbrev-commit FETCH_HEAD * commit d62f68e | Author: NAGAYASU Shinya | AuthorDate: Fri Jan 27 16:15:23 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Fri Jan 27 16:15:23 2023 +0900 | | ime 追加 | | * commit 733e90d (HEAD -\u0026gt; master, origin/master, origin/HEAD) | | Author: NAGAYASU Shinya | | AuthorDate: Thu Jan 26 00:03:14 2023 +0900 | | Commit: NAGAYASU Shinya | | CommitDate: Thu Jan 26 00:03:14 2023 +0900 | | | | elisp/ elpa/ を無視しないように修正 | | | * commit d96b8b2 | | Author: NAGAYASU Shinya | | AuthorDate: Wed Jan 25 23:45:14 2023 +0900 | | Commit: NAGAYASU Shinya | | CommitDate: Wed Jan 25 23:52:03 2023 +0900 | | | | C-h をバックスペースに変更 | | | * commit 7fb8ef8 |/ Author: NAGAYASU Shinya | AuthorDate: Tue Jan 24 23:27:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Tue Jan 24 23:27:02 2023 +0900 | | magit を追加してみた | * commit dad82e3 | Author: NAGAYASU Shinya | AuthorDate: Mon Jan 23 23:46:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Mon Jan 23 23:46:02 2023 +0900 | | いくつかの変数をダイナミックバインディングに変更 | まずは FETCH_HEAD に移動します。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 $ git checkout FETCH_HEAD $ git log --graph --decorate --pretty=fuller --all --abbrev-commit * commit d62f68e (HEAD) | Author: NAGAYASU Shinya | AuthorDate: Fri Jan 27 16:15:23 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Fri Jan 27 16:15:23 2023 +0900 | | ime 追加 | | * commit 733e90d (origin/master, origin/HEAD, master) | | Author: NAGAYASU Shinya | | AuthorDate: Thu Jan 26 00:03:14 2023 +0900 | | Commit: NAGAYASU Shinya | | CommitDate: Thu Jan 26 00:03:14 2023 +0900 | | | | elisp/ elpa/ を無視しないように修正 | | | * commit d96b8b2 | | Author: NAGAYASU Shinya | | AuthorDate: Wed Jan 25 23:45:14 2023 +0900 | | Commit: NAGAYASU Shinya | | CommitDate: Wed Jan 25 23:52:03 2023 +0900 | | | | C-h をバックスペースに変更 | | | * commit 7fb8ef8 |/ Author: NAGAYASU Shinya | AuthorDate: Tue Jan 24 23:27:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Tue Jan 24 23:27:02 2023 +0900 | | magit を追加してみた | * commit dad82e3 | Author: NAGAYASU Shinya | AuthorDate: Mon Jan 23 23:46:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Mon Jan 23 23:46:02 2023 +0900 | | いくつかの変数をダイナミックバインディングに変更 | rebaseして分岐元をずらします。 期待通りログが一本化できました。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 $ git rebase -i origin/master $ git log --graph --decorate --pretty=fuller --all --abbrev-commit * commit 0d325ce (HEAD) | Author: NAGAYASU Shinya | AuthorDate: Fri Jan 27 16:15:23 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Sun Jan 29 19:27:48 2023 +0900 | | ime 追加 | * commit 733e90d (origin/master, origin/HEAD, master) | Author: NAGAYASU Shinya | AuthorDate: Thu Jan 26 00:03:14 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Thu Jan 26 00:03:14 2023 +0900 | | elisp/ elpa/ を無視しないように修正 | * commit d96b8b2 | Author: NAGAYASU Shinya | AuthorDate: Wed Jan 25 23:45:14 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Wed Jan 25 23:52:03 2023 +0900 | | C-h をバックスペースに変更 | * commit 7fb8ef8 | Author: NAGAYASU Shinya | AuthorDate: Tue Jan 24 23:27:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Tue Jan 24 23:27:02 2023 +0900 | | magit を追加してみた | * commit dad82e3 | Author: NAGAYASU Shinya | AuthorDate: Mon Jan 23 23:46:02 2023 +0900 | Commit: NAGAYASU Shinya | CommitDate: Mon Jan 23 23:46:02 2023 +0900 | | いくつかの変数をダイナミックバインディングに変更 | まとめ 今回はGit でリモートリポジトリを共有できないときのコードの共有方法を説明しました。 git bundle でコミットした情報を１つのファイルにまとめそれを共有します。 あとは受け取り側でfetchすればコードが共有できます。 もしブランチが枝分かれしたりしたらrebaseなどで調整してください\n詳細は 7.12 Git のさまざまなツール - バンドルファイルの作成 参照してみてください。\n","permalink":"https://nagayasu-shinya.github.io/posts/git-bundle-offline-sharing/","summary":"\u003cp\u003eネットワークなどの理由でサーバにアクセスできないときにGit のコミット情報を送るときに使える便利機能 \u003ccode\u003egit bundle\u003c/code\u003eについて説明します。\u003c/p\u003e","title":"git bundle でリモートリポジトリを使わずにコミットを共有する"},{"content":"プロキシ環境下でDockerを使うための設定方法を、apt Docker デーモン・コンテナの3箇所に分けて説明します。\napt 周りのプロキシ設定 この記事の確認環境は WSL Ubuntu20.04です。\n1 2 3 4 5 6 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.4 LTS Release: 20.04 Codename: focal まず、WSLのProxy設定方法 の記事を参考に設定してください。 WSL でもUbuntuでも同じです。特に apt.conf の設定を忘れないでください。 ここを間違えると下記のように「そんなもんDockerリポジトリには存在せんぞ」と怒られてしまいます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ sudo add-apt-repository \\ \u0026#34;deb [arch=amd64] https://download.docker.com/linux/ubuntu \\ $(lsb_release -cs) \\ stable\u0026#34; $ sudo apt-get update Ign:1 https://download.docker.com/linux/ubuntu focal InRelease Err:2 https://download.docker.com/linux/ubuntu focal Release Could not handshake: An unexpected TLS packet was received. [IP: XX.XX.XX.XX:YY] Hit:3 http://security.ubuntu.com/ubuntu focal-security InRelease Get:4 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB] Get:5 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB] Get:6 http://archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB] Reading package lists... Done E: The repository \u0026#39;https://download.docker.com/linux/ubuntu focal Release\u0026#39; does not have a Release file. N: Updating from such a repository can\u0026#39;t be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. DockerデーモンのProxy設定 さらに/etc/default/dockerの修正が必要です。そこにコメントアウトされた状態でProxyの設定例が書いてあります。そこを自分の環境に合わせて修正します。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ cat /etc/default/docker # Docker Upstart and SysVinit configuration file # # THIS FILE DOES NOT APPLY TO SYSTEMD # # Please see the documentation for \u0026#34;systemd drop-ins\u0026#34;: # https://docs.docker.com/engine/admin/systemd/ # # Customize location of Docker binary (especially for development testing). #DOCKERD=\u0026#34;/usr/local/bin/dockerd\u0026#34; # Use DOCKER_OPTS to modify the daemon startup options. #DOCKER_OPTS=\u0026#34;--dns 8.8.8.8 --dns 8.8.4.4\u0026#34; # If you need Docker to use an HTTP proxy, it can also be specified here. export http_proxy=\u0026#34;http://username:password@proxy-host:proxy-port\u0026#34; export https_proxy=\u0026#34;http://username:password@proxy-host:proxy-port\u0026#34; export ftp_proxy=\u0026#34;http://username:password@proxy-host:proxy-port\u0026#34; # This is also a handy place to tweak where Docker\u0026#39;s temporary files go. #export DOCKER_TMPDIR=\u0026#34;/mnt/bigdrive/docker-tmp\u0026#34; さらに、systemctl の設定も行います。\n1 sudo systemctl edit docker と実行するとエディタが開きますので下記のようにProxyを設定してください。\n1 2 3 [Service] Environment=\u0026#34;HTTP_PROXY=http://proxy-host:proxy-port/\u0026#34; Environment=\u0026#34;HTTPS_PROXY=http://proxy-host:proxy-port/\u0026#34; コンテナ起動時のプロキシ設定 コンテナの作成もしくは起動時に、環境変数がコンテナ内へ自動的に設定するように設定ファイルを作成します。 プロキシサーバを使うように Docker を設定にあるようにホスト側に ~/.docker/config.json を作ればOKです。 下記のような感じですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ mkdir -p ~/.docker/ $ vim ~/.docker/config.json $ cat ~/.docker/config.json { \u0026#34;proxies\u0026#34;: { \u0026#34;default\u0026#34;: { \u0026#34;httpProxy\u0026#34;: \u0026#34;http://192.168.1.12:3128\u0026#34;, \u0026#34;httpsProxy\u0026#34;: \u0026#34;http://192.168.1.12:3128\u0026#34;, \u0026#34;noProxy\u0026#34;: \u0026#34;*.test.example.com,.example2.com,127.0.0.0/8\u0026#34; } } } まとめ これでDockerイメージをプルしてHello Worldまではできるようになったはずです。\n","permalink":"https://nagayasu-shinya.github.io/posts/docker-proxy-configuration/","summary":"\u003cp\u003eプロキシ環境下でDockerを使うための設定方法を、\u003ccode\u003eapt\u003c/code\u003e \u003ccode\u003eDocker\u003c/code\u003e デーモン・コンテナの3箇所に分けて説明します。\u003c/p\u003e","title":"Docker の Proxy初期設定"},{"content":"Ubuntuではデフォルトでは bash でなく dash が使われています。 スクリプトから bashに変更できる方法を説明します。\n背景 Ubuntuはデフォルトシェルが dashで、それで困ることはそれほど多くないのですが bash が好きな方もいるかと思います。 また、ちゃんとシェバンを書いていないお行儀の悪いスクリプトがいたりすると困ってしまいます。 Bashism あふれるスクリプトなのにシェバンが #!/bin/sh となっていたら殺意すら覚えます。\nそこで今回は、まず一般的に解説されているUbuntuのデフォルトのシェルをbashにする方法を説明します。 その方法は dpkg-reconfigure を使いますが、この方法はインタラクティブなコマンドなのではスクリプトでは使えません。 そこでさらにスクリプトで使える代替の方法も説明します。\nちなみに確認環境は WSL Ubuntu20.04です。\n1 2 3 4 5 6 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.4 LTS Release: 20.04 Codename: focal 簡単な方法 下記のように実行します。\n1 sudo dpkg-reconfigure dash 環境や言語設定によって表示が違いますが「dash をデフォルトのシステムシェル（/bin/sh）として使いますか？」という意味のことを聞かれるので「No」「いいえ」を選択します（環境によって「No」と入力する場合もあります）。 実行したら念のため、/bin/sh を確認します。下記のように bash を指していれば問題ありません。\n1 2 $ ls -l /bin/sh lrwxrwxrwx 1 root root 4 3月 10 00:31 /bin/sh -\u0026gt; bash スクリプトでも使える方法 上記の dpkg-reconfigure ですが、No と選択する必要があるためスクリプトでは使えません。ならばと下記のように Yes コマンドを使ってみてもダメでした。\n1 yes \u0026#34;no\u0026#34; | sudo dpkg-reconfigure dash 代わりに下記のように実行すれば上記と同じことができます。選択が不要になるのでこのままスクリプトに使えます。\n1 2 echo \u0026#34;dash dash/sh boolean false\u0026#34; | debconf-set-selections DEBIAN_FRONTEND=noninteractive dpkg-reconfigure dash 実行後に /bin/sh を確認するとちゃんと bash を指しているはずです。 コマンドの詳細は下記にかいてありました。 https://superuser.com/questions/715722/how-to-do-dpkg-reconfigure-dash-as-bash-automatically\nDockerfile での書き方 スクリプトで書けないと Dockerfile でも困ってしまいます。Dockerfile では下記のようにすればOKです。\n1 2 RUN echo \u0026#34;dash dash/sh boolean false\u0026#34; | debconf-set-selections RUN DEBIAN_FRONTEND=noninteractive dpkg-reconfigure dash まとめ Ubuntu（WSL含む）でのデフォルトシェルを bash に変更する方法を説明しました。 一般的に使われている dpkg-reconfigure はスクリプトでは使えないのでその代替の方法も説明しました。 参考になれば幸いです。\n","permalink":"https://nagayasu-shinya.github.io/posts/ubuntu-default-shell-bash/","summary":"\u003cp\u003eUbuntuではデフォルトでは \u003ccode\u003ebash\u003c/code\u003e でなく \u003ccode\u003edash\u003c/code\u003e が使われています。\nスクリプトから \u003ccode\u003ebash\u003c/code\u003eに変更できる方法を説明します。\u003c/p\u003e","title":"Ubuntuのデフォルトシェルをスクリプトから変更する"},{"content":"今回はWindowsからWSL上のファイルに便利にアクセスする方法を書きます。\nエクスプローラーで \\\\wsl\\$ と入力する 一番普通のやりかたですね。エクスプローラーのアドレスバーに \\\\wsl\\$ と入力する方法です。 たとえばUbuntu20.04を使っているなら下記のような感じです。これでWSLのルートディレクトリにアクセスできます。簡単。\nネットワークドライブを割り当てる 上記の方法でもいいんですが、Windows 上で動くツールの中には\\\\wsl\\$で始まるアドレスを受け付けないものもあります。 Cドライブなどの下にファイルがあることが前提になっているツールがちらほらあります。 また、毎回アドレスバーに入力するのも面倒です。そこでネットワークドライブを利用します。\nまずはじめに WSL のパスをコピーします。下記では \\\\wsl\\$\\Ubuntu-20.04 ですね。\nつぎにエクスプローラーの左側のナビゲーションウィンドウで 「PC」を右クリックします。 「ネットワークドライブの割り当て」 を選択します。下記のような感じ。\nするとネットワークドライブのドライブ文字とフォルダーを指定するように言われます。 フォルダーには先ほどコピーした\\\\wsl\\$\\Ubuntu-20.04を入れます。ドライブ文字の方は任意です。なんでもいいです。下記の例ではGにしています。\nこれで下記のようにネットワークドライブ（この例でG:ドライブ）が追加されます。\n念のためにネットワークドライブをダブルクリックしてWSL上のファイルにアクセスできることを確認しておきましょう。\nこれで次からはWSL上のファイルをG:ドライブとしてアクセスできるようになりました。何かとこっちのほうが便利だと思います。 上記はWindows10での方法ですがWindows11でも基本変わらないと思います。いちおう公式サイトにある Windows 10 におけるネットワーク経由のファイル共有の記事を貼っておきますね。\nおまけ｜WSLからエクスプローラーを開く あまり使う場面は無いかもしれませんが WSLからコマンドでエクスプローラーを開けます。下記のようにexeを実行するだけです。ご参考まで。\n1 explorer.exe まとめ WSL 上のファイルをエクスプローラからアクセスする方法を説明しました。また、\\\\wsl\\$と毎回アドレスバーに入力するのも面倒ですし、 そのようなパスに対応していないツールなんかもたまにあるので、それをネットワークドライブに割り当てる方法も説明しました。 ご参考になれば幸いです。\n","permalink":"https://nagayasu-shinya.github.io/posts/wsl-network-drive-mapping/","summary":"\u003cp\u003e今回はWindowsからWSL上のファイルに便利にアクセスする方法を書きます。\u003c/p\u003e","title":"WSLをネットワークドライブに割り当てて便利に使う方法"},{"content":"４月になったので新社会人になったひとも多いかと思います。そういう人に向けて社会人歴１５年のおじさんがやっておいたほうがいいことを書き並べてみます。参考にしてみてください。\n就業規則を確認しておこう 会社には就業規則というものがあります。 その会社で働く上でのルールが書いてあります。会社からわれわれ労働者に課せられる決まり以外に労働者が行使できる権利も書いてあります。 これを把握しておかないと一人前の社会人とは言えません。まっさきに確認しておくべき項目をあげておきますので会社で確認してみてください。 ちなみに就業規則は社員が閲覧できるようにせよと法律で決まっているので閲覧できないことはないはずです。だいたいイントラから参照できるようになっていると思います。 もしかしたら就業規則でなく労働協約書のほうに書いてあるかもしれません。両方確認しておけば問題ないです。\n有給休暇 労働者の権利として有給休暇というものがあります。お仕事休んでもお賃金をくれるという素敵な制度です。これを確認しましょう。 労働基準法で最低限労働者に与えるべき日数が決まっています。福利厚生がつよい会社では労基法以上の日数をくれます。就業規則に書いてあるので確認してください。\n一年あたりの付与日数 繰越できる日数の上限 半日休暇はあるか 時間単位休暇はあるか ちなみにですが有給休暇をとるのに理由はいりません。なんとなく休みたいからという理由でOKです。 まあ馬鹿正直に「仕事行きたくないんで休みます」とかいうと角が立つので「家庭の事情で」とか「役所に行きたいので」とか言っておけばいいと思います。\n休職 不幸にして大きな怪我や病気をして長期間（何ヶ月も）休むことになった場合の制度です。 人生いつ何があるかわからないので元気なうちに制度を把握しておきましょう。 休める最長期間などを見ておきましょう。 その期間内に復職できなかった場合の扱いも確認必要です。残念ながら会社をやめることになります。\n休職は有給休暇とちがってお給料は出ません。 じゃあどうやって生活するのかという心配が出てきますが大丈夫です。健康保険がお金くれます。傷病手当という制度です。ざっくり月給の2/3の額がもらえます。\n税金社会保険などに敏感になろう 頑張って労働してお給料もらっても残念ながらから税金や社会保険、年金が天引きされます。信じられないことに月給の3〜4割くらい持っていかれます。おそらく支出で一番でかい項目です。次が家賃ですかね。つまり国からギュウギュウに搾り取られた残りを資本家に貢がされる人生になります。悲しいですね。\n住民税に気をつけろ 住民税というものがあります。これは前年の給料に対してかけられるものです。なので社会人1年目は取られません。2年目から取られます。なので1年目でカツカツの生活を送っていると2年目でお金が足りなくなります。気をつけよう。\n標準報酬月額を意識しよう 社会保険料というものがあります。これらは標準報酬月額をもとに額が決まります。 ざっくりいうと標準報酬月額は4月5月6月の給料の平均です。 なので3月4月5月にたくさん残業してその翌月の4月5月6月にお給料をたくさんもらうと標準報酬月額も高くなり保険料も上がります。 なので3月4月5月はあんまり頑張らないほうがいいですね。12ヶ月の平均を出せばいいのに、とは思います。 ちなみにこの標準報酬月額には福利厚生も含まれます。\n最近よくある福利厚生のカフェテリアプランなどが要注意です。 これは１年間あたり一定額まで福利厚生として費用を補助してくれる制度です。 対象は書籍や旅行、資格取得やフィットネスなどの費用です。 たとえば年間１２万円まで補助してくれる場合、それを全額４月５月６月に受け取ってしまうと４万円お給料が上がったと同じことになってしまいます。 使うなら別の月にしましょう。\nちなみに標準報酬月額が上がるといいこともあって、たとえば傷病手当金は標準報酬月額をもとに計算するのでチョットお得になります。\n確定拠出年金を活用しよう 最近は確定拠出年金を採用する企業が多いです。 自分で投資を運用して年金を準備する制度です。 こいつのいいところは税金を抑えることができるところです。 普通に株などで儲けたら２割税金で持っていかれますが確定拠出年金は非課税です。また所得税や住民税も安くなります。\n拠出した額は所得税住民税がかかりません。たとえば毎月２万円拠出したとして所得税が２０％、住民税が１０%としたら2 * 12 * (0.2 + 0.1) = 72000円儲かります。 拠出できる額の上限はありますが可能な限り拠出しておくことをおすすめします。 自分で給料から定期預金に積み立てるよりよっぽど儲かります。 注意点としては確定拠出年金は定年まで使えないことです。定年までお金が必要になっても使えません。\nクレジットカードは2枚つくろう クレジットカードを作る人も多いかと思います。VISAかMaster,JCBブランドですきなものを選べばいいです。 できれば２枚持つことをおすすめします。１枚を普段使いとして財布にいれておき、もう１枚は家賃や公共料金、水道光熱費など用にして家に置いておくといいです。 １枚だけで家賃や公共料金なども払っているとうっかり財布を落としたときにかなり困ります。手続きがマジでめんどいです。\nリボ払いダメ絶対 クレジットカードで絶対避けるべきことがあります。リボ払いです。毎月定額だけ返済していく方式ですが利率がやばいです。 １５％くらい持っていかれます。サラ金なみです。それだけカード会社はもうかるのであの手この手でリボ払いさせようとしてきますが断固として断りましょう。\n民間保険 さいきんはコロナで見かけなくなりましたが、チョット前までは社内の食堂や売店の近くに生命保険のお姉さんたちがいました。 執拗に保険をすすめてきます。まあ保険に入るのもありとはおもいますがものすごく高い買い物だということは頭に入れておいてください。 毎月払い続けるものなので数百万円にのぼります。だからお姉さんたちが執拗に勧誘してくるわけです。 どの保険が必要なのかは前述した傷病手当なども踏まえて検討したほうがいいでしょう。 また、共済などの保険も選択肢にいれたほうがいいですね。やすいので。\n転職に備える 自分に非がなくても市況が悪化したとか経営層が粉飾決算したとかで転職を余儀なくされることがあります。 若いひとは比較的クビを切られにくいですが絶対安全とは言えません。備えておきましょう。\n職務経歴をメモしておこう 具体的には半年に一回、上期と下期が終わるたびに職務経歴書を更新するといいかと思います。 経歴書をつくるのが面倒なら半年で何をしたかをメモっておきましょう。 数年後にいざ転職しようとしたとき、記録がなにもないとなにをしてきたか意外に思い出せないです。考課査定とか期初目標のシートなどがあればそれも保存しておきましょう。 転職しなくても自分のキャリアの棚卸しになるのでかなりおすすめです。漠然と仕事していると運がわるいと詰みますよ。\n資格は取っておこう 歳を取ると物覚えが悪くなります。学生のとき勉強したことも忘れています。 仕事以外の家庭で時間も取られます。資格取得はどんどんむずかしくなっていきます。 なので若いうちに取っておきましょう。資格はあるにこしたことはないです。おすすめは日商簿記です。 ３級の知識は主任昇格試験とかでもでるので無駄にならないです。基本情報技術者ももっておいて損はないです。 あと都会で育った人が意外に持っていないことありますが運転免許もあったほうがいいです。 地方に転勤になったときに困ってしまいます、地方は電車なんか来ないんじゃ。 今パッと思いつくおすすめ資格を挙げておきます。ソフトエンジニア向けです。\n普通運転免許 日商簿記３級・２級 基本情報技術者・応用情報技術者 ITIL LPIC もし講座をとって勉強する際には教育給付金という制度があるそうです。 昔は失業者だけが対象だったように記憶していますがいまは在籍者でも使えるそうです。詳しくはググってみてください。\n同期を大事に おそらく人生最後の損得勘定のない友人になる可能性が大です。 １０年２０年たっても変わらず付き合いのあるのは同期だけになるんじゃないかと。若いときはピンとこないですけど、あとから同期の存在はきいてきます。\n転職しても新卒の同期は付き合があることが多いです。同じ会社はいって同じようなタイミングで人生のイベントを進めていくことになるので同じ釜の飯を食ったという感じになります。 また同期は全然関係ない部署でも仲良くなることがあるので純粋に人脈という意味でも重要です。さきに同期に話を通しておいてから他部署とネゴするとスムーズに行く場合もあります。 もちろん人間なんで合う合わないはありますが、すくなくとも後ろから刺すような真似はやめておきましょう。\n趣味を持とう 会社と自宅の往復では人生が単調になります。また仕事がうまくいかないときに会社にしか居場所がないとメンタルがやられてしまいます。 居場所が会社だけというのはかなりリスクが高いです。いつも仕事が順風満帆とは限りません。会社以外に居場所を作りましょう。\n趣味は何でもいいんですがチームや団体に所属すると精神衛生上いいとおもいます。 一人でやる趣味ももちろんいいですが、居場所を作るという意味ではなにか複数人でやるのがいいかなと思います。 近くの市民体育館とかにいくと掲示板でメンバーを募集してたりするので見てみるといいかと思います。 例えばフットサルはやっている人おおいですね。自転車も多いですね。あと武道格闘技も最近は意外に多い。いろいろやってみて自分似合うものをやればいいと思います。\nまとめ 思いついたことをつらつらと書いてみました。まとまりのない内容になってしまいましたが、参考になればさいわいです。\n","permalink":"https://nagayasu-shinya.github.io/posts/new-employee-workplace-tips/","summary":"\u003cp\u003e４月になったので新社会人になったひとも多いかと思います。そういう人に向けて社会人歴１５年のおじさんがやっておいたほうがいいことを書き並べてみます。参考にしてみてください。\u003c/p\u003e","title":"新入社員のひとにおくるいろいろな小技"},{"content":"色付きのハイライトにて実行結果を表示するコマンドが多くありますが、その結果を色付きのままHTMLで保存する方法を説明します。\nLinuxやWSLなどでコマンドを実行したとき、出力がカラーで表示されることがあると思います。 たとえばls --color=autoとかですね。このような出力を普通にリダイレクションなどでファイルに書き込むと色情報が失われて普通の文字になってしまいます。 lsだったら別にそれで困らないと思いますが、色がないとわかりづらい diff のようなコマンドの出力だと色情報ごと保存したいときもあると思います。 そのような場合において今回はコマンド出力をHTMLに変換して色ごと保存する方法を説明します。\n色付き文字を出力する方法 まず最初に基礎知識として文字に色を付ける方法を簡単に説明します。 ANSIエスケープシーケンスを使います。そんなの知っているよ！というかたは飛ばしてOKです。\nASCII コード 通常文字（アルファベットと記号と数字。いったん日本語文字は置いておいてください）を出力をするにはASCIIコードを用います。 CPUは結局数値しか扱えないので文字を表現しようとすると数値を文字に対応させる必要があります。\nその対応表がASCIIコード表と呼ばれるものです。たとえば「A」は65、「B」は66、「C」は67\u0026hellip;.　となっています。 実際のASCIIコード表はググれば出てきます。Wikipedia - ASCIIなどが参考になるかと思います。 いろいろむずかしいこと書かれていますが、要は「ASCII印字可能文字」のところの表に合わせて数字を文字として解釈するよ、というだけの話です。\n実際に試してみることも可能です。下記のコマンドでは0x41 0x42 0x43（10進で65, 66,67）を出力しています。 結果はASCIIコード表どおりA B Cとなります。\n1 2 $ echo -e \u0026#34;\\x41 \\x42 \\x43\u0026#34; A B C ANSI エスケープシーケンス 上記の方法で文字を出力できることはわかりました。さらにそれに色を付ける方法があります。 ANSI エスケープシーケンスと呼ばれているものを付加します。 まず最初にANSIエスケープシーケンスを利用したコマンドとその結果を示します。\n1 2 $ echo -e \u0026#34;\\x1b[31;47m\\x41 \\x42 \\x43\\x1b[0m\u0026#34; A B C 上記だと色がわからないと思うのでキャプチャを貼ります。白背景に赤文字になりました。\n上記のコマンド例での \\x1bがエスケープコードと言われるものです。 16進数で0x1b、8進だと033です。このエスケープコードがエスケープシーケンスの始まりを示します。 上記の例だと\\x1b\\[31;47m と \\x1b\\[0m がエスケープシーケンスです。\nエスケープコードに続く [ は CSI (Control Sequence Introducer)と呼ばれるもので制御シーケンスの始まりを示します。 エスケープシーケンスのうち \\[31;47m と \\[0m がそれに該当します。\nまた制御シーケンスが mで終わる場合は SGR (Select Graphic Rendition)、表示様式選択とよばれます。 これを使って文字と背景色を設定しています。\\[31;47mのうち 31が文字色を設定しているところで赤を表します。 47が背景色を設定しているところで白を表します。ココの値をかえると色を変更できます。\nちなみに2つ目のSGR の 0はリセットです。これがないとずっと色設定をしたままになってしまいます。 わかりづらいとおもうので上記の色付きで出力するコマンドをちょっと書き換えると下記のようになります。\n1 echo -e \u0026#34;\\x1b[色設定;色設定m ＜色付きで出力したい文字列＞ \\x1b[0m\u0026#34; 色設定についてはWikipediaのANSI_escape_code - 3-bit and 4-bitの表を参照してください。 FGが文字色、BGが背景色です。\nちなみにですがエスケープコードは \\eと書くこともできます。どちらでも同じ意味です。\n1 echo -e \u0026#34;\\e[31;47m\\x41 \\x42 \\x43\\e[0m\u0026#34; 補足 もうちょっと詳しく知りたい方は碧色工房 - ANSIエスケープコードが参考になるかと思います。 簡単なC言語で説明してあります。\nさらに詳しく知りたい人は規格を確認してください。色以外にもいろんなことができます。規格はISO/IEC 6429 です。 その日本語訳がJISで定められています。JIS X0211です。 JIS検索から X0211で検索すれば日本語のPDFが閲覧できます（ダウンロードとか印刷はNGらしい）。\nコマンド出力の確認 色付き文字で出力するコマンドも上記のANSI エスケープシーケンスを使っています。それを確認してみたいと思います。 ためしに ls コマンドを色付きで出力してみます。下記のようになりますね。ちなみに最初のバックスラッシュは素の ls を実行するためです。これがないと .bashrc などで設定されたエイリアスを実行することがあるためつけています。\n次にこの実行結果をlessに渡してみましょう。 下記のようにリダイレクションすればOKです。 このとき --color=always は必ずつけてください。理由は後で述べます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 $ \\ls -laF --color=always | \\less 合計 128 drwxrwxr-x 29 shinya shinya 4096 3月 30 01:29 ESC[0mESC[01;34m.ESC[0m/ drwxr-xr-x 14 shinya shinya 4096 3月 2 22:05 ESC[01;34m..ESC[0m/ drwxrwxr-x 2 shinya shinya 4096 6月 18 2021 ESC[01;34m.bootstrapESC[0m/ drwxrwxr-x 7 shinya shinya 4096 6月 18 2021 ESC[01;34m.repoESC[0m/ lrwxrwxrwx 1 shinya shinya 19 6月 26 2021 ESC[01;36mAndroid.bpESC[0m -\u0026gt; build/soong/root.bp lrwxrwxrwx 1 shinya shinya 23 6月 26 2021 ESC[01;36mBUILDESC[0m -\u0026gt; build/bazel/bazel.BUILD lrwxrwxrwx 1 shinya shinya 27 6月 26 2021 ESC[01;36mWORKSPACEESC[0m -\u0026gt; build/bazel/bazel.WORKSPACE -rw-rw-r-- 1 shinya shinya 2607 3月 30 01:20 a.txt drwxrwxr-x 38 shinya shinya 4096 9月 30 23:41 ESC[01;34martESC[0m/ drwxrwxr-x 15 shinya shinya 4096 9月 30 23:41 ESC[01;34mbionicESC[0m/ drwxrwxr-x 4 shinya shinya 4096 6月 26 2021 ESC[01;34mbootableESC[0m/ lrwxrwxrwx 1 shinya shinya 26 6月 26 2021 ESC[01;36mbootstrap.bashESC[0m -\u0026gt; ESC[01;32mbuild/soong/bootstrap.bashESC[0m* drwxrwxr-x 8 shinya shinya 4096 9月 30 23:41 ESC[01;34mbuildESC[0m/ drwxrwxr-x 3 shinya shinya 4096 6月 26 2021 ESC[01;34mcompatibilityESC[0m/ drwxrwxr-x 14 shinya shinya 4096 6月 26 2021 ESC[01;34mctsESC[0m/ drwxrwxr-x 8 shinya shinya 4096 9月 30 23:41 ESC[01;34mdalvikESC[0m/ drwxrwxr-x 5 shinya shinya 4096 6月 26 2021 ESC[01;34mdevelopersESC[0m/ drwxrwxr-x 21 shinya shinya 4096 9月 30 23:41 ESC[01;34mdevelopmentESC[0m/ drwxrwxr-x 11 shinya shinya 4096 6月 26 2021 ESC[01;34mdeviceESC[0m/ drwxrwxr-x 347 shinya shinya 12288 9月 30 23:41 ESC[01;34mexternalESC[0m/ drwxrwxr-x 16 shinya shinya 4096 6月 26 2021 ESC[01;34mframeworksESC[0m/ -rw-rw-r-- 1 shinya shinya 0 3月 29 20:44 fuga.html drwxrwxr-x 15 shinya shinya 4096 6月 26 2021 ESC[01;34mhardwareESC[0m/ drwxrwxr-x 5 shinya shinya 4096 6月 26 2021 ESC[01;34mkernelESC[0m/ drwxrwxr-x 20 shinya shinya 4096 9月 30 23:41 ESC[01;34mlibcoreESC[0m/ drwxrwxr-x 10 shinya shinya 4096 6月 26 2021 ESC[01;34mlibnativehelperESC[0m/ -rw-rw-r-- 1 shinya shinya 0 3月 30 01:29 ls_color.txt drwxrwxr-x 9 shinya shinya 4096 6月 26 2021 ESC[01;34mpackagesESC[0m/ drwxrwxr-x 6 shinya shinya 4096 6月 26 2021 ESC[01;34mpdkESC[0m/ drwxrwxr-x 10 shinya shinya 4096 6月 26 2021 ESC[01;34mplatform_testingESC[0m/ drwxrwxr-x 32 shinya shinya 4096 9月 30 23:41 ESC[01;34mprebuiltsESC[0m/ drwxrwxr-x 22 shinya shinya 4096 6月 26 2021 ESC[01;34msdkESC[0m/ drwxrwxr-x 46 shinya shinya 4096 7月 30 2021 ESC[01;34msystemESC[0m/ drwxrwxr-x 11 shinya shinya 4096 6月 26 2021 ESC[01;34mtestESC[0m/ drwxrwxr-x 4 shinya shinya 4096 6月 26 2021 ESC[01;34mtoolchainESC[0m/ drwxrwxr-x 24 shinya shinya 4096 6月 26 2021 ESC[01;34mtoolsESC[0m/ 注目してほしいのは ESCとあるところです。これが前述したANSIエスケープシーケンスです。 よく出てくるESC\\[01;34m について説明すると 01は太字、34は青色を指定しています。\nちなみに --color=alwaysをつけない場合（デフォルト）は、パイプの場合エスケープシーケンスは出力されません。 lsが気を遣って出力しません。lessもそうでしたが、パイプ先がエスケープシーケンスを扱えるとは限らないためです。\n補足ですが catはエスケープシーケンスを扱えます。 下記のようにしてみてください。色付きで出力されるはずです。\n1 \\ls -laF --color=always | cat ANSIエスケープシーケンスをHTMLに変換する 色付きのコマンド出力は ANSI エスケープシーケンスを使っていることを説明しました。これを色付きのまま保存するにはHTMLに変換するのが楽ちんです。HTMLならブラウザで簡単に見れますしね。 ここではansi2html というコマンドを使います。\nansi2html インストールは Ubuntu なら apt install でできます。 手元のUbuntu20.04だと下記のコマンドでインストールできました。 ansi2html と打ってみるとどうやってインストールするか教えてくれると思います。\n1 sudo apt install colorized-logs 使い方は簡単です。下記のようにパイプでANSIエスケープのログを渡すだけでOKです。HTMLが出力されますので任意の名前でファイルの保存すればOKです。\n1 \\ls -laF --color=always | ansi2html \u0026gt; ls_color.html 下記は出力したHTMLをブラウザで表示しています。ちゃんと色も出力されていますね。期待通りです。\n特に使い方で迷うことはないと思いますが、詳細はansi2htmlを参照してください。\nページャーとバッファリング lsの場合は上記の方法でOKです。次はもう少し複雑な例を見てみます。 例として repo というツールの出力を考えます。 repo は Gitのフロントエンドで、 数百以上のリポジトリからなるAndoroid AOSPのようなプロジェクトを扱うためのツールです。 例えば下記のように実行すれば色付きでandroid-12.1.0_r2 のバージョンと現在のバージョの差分を出力してくれます。\n1 repo diffmanifests android-12.1.0_r2.xml default.xml 出力はこんな感じです。\nこの出力を色付きのままHTMLに保存することを考えます。\nunbuffer repo diffmanifests コマンドもデフォルトの lsと同じように標準出力以外への出力の際はANSIエスケープシーケンスを出力しません。 色なしになります。例えば下記のようにパイプを使うと色なしの出力になります。\n1 repo diffmanifests android-12.1.0_r2.xml default.xml | cat ls の場合は出力先が標準出力以外でも常に色付きで出力するオプション --color=always がありました。 しかし repo diffmanifestsにはありません。 そのためさらに別のツールが必要になります。 unbuffer というツールがそれを可能にします。インストールはUbuntuの場合は下記のようにすればOKです。\n1 sudo apt install expect 使い方も簡単です。unbuffer に色付きで出力したいコマンドを渡すだけです。\n1 unbuffer -p repo diffmanifests android-12.1.0_r2.xml default.xml | cat このように色付きで出力されるようになります。\nページャー 上記で色付きで出力できるようになったので下記のようにリダイレクションで結果をファイルに保存したとします。\n1 unbuffer -p repo diffmanifests android-12.1.0_r2.xml default.xml | ansi2html \u0026gt; diffmanifests.html 残念ながらこのままでは動作しません。待てど暮せどコマンドが終了しないはずです。 実はless が起動してしまっておりコマンド待の状態になっているためです。 lessなのでqを押すと終了します。 ここでは一気に全部出力してほしいのでless でなく cat を使うようにすればOKです。 その設定は環境変数 PAGERで指定できます。ページャーと呼ばれる設定で、下記のように PAGER に catを設定して実行すればOKです。\n1 PAGER=cat unbuffer -p repo diffmanifests android-12.1.0_r2.xml default.xml | ansi2html \u0026gt; diffmanifests.html これで色付き強制のオプションのないコマンドでも色付きで出力を保存できるようになりました。 出力したHTML をブラウザで開くと色付きで表示されます。\nまとめ 今回は最初に文字に色を付けるためのANSIエスケープシーケンスについて簡単に説明しました。 そしてコマンドの出力を色付きで保存する方法を説明しました。基本はansi2htmlコマンドに渡してHTMLにすればOKです。\nリダイレクションするとANSIエスケープシーケンスを抑止して色なしになってしまうコマンドではunbuffer をさらに使えばOKです。 ページャーが less 担っている場合は PAGER環境変数を cat にすればOKです。 この方法は大抵のコマンドで使えると思います。いろんなコマンドで試してみてください。\n","permalink":"https://nagayasu-shinya.github.io/posts/ansi-color-html-conversion/","summary":"\u003cp\u003e色付きのハイライトにて実行結果を表示するコマンドが多くありますが、その結果を色付きのままHTMLで保存する方法を説明します。\u003c/p\u003e","title":"コマンド出力を色付きのまま保存する | ansi2html と unbuffer"},{"content":"jenkinsfile の sh()は素のshなのでbashizmの機能が使えません。 そこでshではなくbashを使う方法を説明します。\nJenkinsfile の sh()は、サイトの Pipeline: Nodes and Processes - sh: Shell Script の説明にあるとおり「Runs a Bourne shell script」です。つまり bash ではありません。 なので、たとえば下記のようにbashismなプロセス置換機能を使うとエラーとなります。\n1 2 String hoge = sh(returnStdout: true, script: \u0026#34;while read v; do echo \\$v; done \u0026lt; \u0026lt;(cat fugafile)\u0026#34;) おそらく syntax error near unexpected token '\u0026lt;'のようなエラーメッセージが出力されると思います。 下記のように /bin/sh を bash に向けていても同じエラーになるようです。\n1 2 $ ls -l /bin/sh lrwxrwxrwx 1 root root 4 3月 10 00:31 /bin/sh -\u0026gt; bash bash を使う方法は簡単で、下記のようにエイヤッとシェバンをつければOKです。これで動作しました。\n1 2 String hoge = sh(returnStdout: true, script:\u0026#34;#!/bin/bash \\n\u0026#34; + \u0026#34;while read v; do echo \\$v; done \u0026lt; \u0026lt;(cat fugafile)\u0026#34;) 言われてみればそりゃそうかと思いますが、ちょっとハマったのでメモしておきます。もし参考になれば幸いです。\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-bash-shell-configuration/","summary":"\u003cp\u003ejenkinsfile の \u003ccode\u003esh()\u003c/code\u003eは素の\u003ccode\u003esh\u003c/code\u003eなのでbashizmの機能が使えません。\nそこで\u003ccode\u003esh\u003c/code\u003eではなく\u003ccode\u003ebash\u003c/code\u003eを使う方法を説明します。\u003c/p\u003e","title":"Jenkinsfile から bash の機能を使う"},{"content":"ちょっとした作業ならシェルスクリプトで行うことも多いと思いますが大きくなるとメンテナンスが大変です。 そこで Jenkins にて静的解析ツールとステップ数計測ツールを実行する方法を説明します。\nShellCheck シェルスクリプトにおいて他言語の Lint に該当するのが ShellCheckです。 公式サイト shellcheck に各OSでのインストールの方法も書かれています。 Ubuntu なら普通に apt install するだけです。\ncloc シェルスクリプトが肥大すると手に負えなくなるので行数も監視したいところです。 今回は、コードのステップ数計測ツール cloc でも紹介した cloc を例として使いたいと思います。\nJenkins プラグイン 上記の２つのツールを扱うために Jenkins に入れる必要のあるプラグインは2つです。 まずステップ数を集計する SLOCCount プラグインをインストールします。普通にプラグインマネージャからインストールすればOKです。\n行数や静的解析の指摘数の推移をグラフで表示するためにWarnings Next Generationをインストールします。 これも普通にプラグインマネージャからインストールすればOKです。\nJenkinsfile の例 では早速 Jenkinsfile のサンプルを示します。この例では2つのGitリポジトリをクローンし、それに対して ShellCheck と cloc を実行しています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 pipeline { agent { label { label \u0026#34;master\u0026#34; /* ワークスペースの設定. 任意の場所でOK. */ customWorkspace \u0026#34;/mnt/SSD/jenkins/$JOB_NAME/\u0026#34; } } stages { stage (\u0026#39;ワークスペースの初期化\u0026#39;) { steps { /* 念のためワークスペースのクリア. */ deleteDir() } } stage (\u0026#39;スクリプトダウンロード\u0026#39;) { steps { /* １つめのリポジトリ. */ sh \u0026#39;mkdir -p hoge\u0026#39; dir(\u0026#34;hoge\u0026#34;) { git branch: \u0026#39;master\u0026#39;, changelog: false, credentialsId: \u0026#39;sample_1\u0026#39;, poll: true, url: \u0026#39;https://git.sample_1.com/hoge.git\u0026#39; sh \u0026#39;git reset --hard\u0026#39; /* 念のため. */ sh \u0026#39;git clean -df\u0026#39; /* 念のため. */ } /* ２つめのリポジトリ. */ sh \u0026#39;mkdir -p fuga\u0026#39; dir(\u0026#34;fuga\u0026#34;) { git branch: \u0026#39;master\u0026#39;, changelog: false, credentialsId: \u0026#39;sample_2\u0026#39;, poll: true, url: \u0026#39;ssh://git.sample_2.com/fuga.git\u0026#39; sh \u0026#39;git reset --hard\u0026#39; /* 念のため. */ sh \u0026#39;git clean -df\u0026#39; /* 念のため. */ } } } stage (\u0026#39;静的解析\u0026#39;) { steps { /* シェバンを検索して bash, sh なら shellcheck を実行. * カレントディレクトリ以下のファイルのステップ数をカウントして xml 形式で出力. * 「\\」のエスケープを忘れずに. */ sh \u0026#39;\u0026#39;\u0026#39; grep -rIl \u0026#39;^#![[:blank:]]*/bin/\\\\(bash\\\\|sh\\\\)\u0026#39; --exclude-dir=.git --exclude=*.sw? | xargs shellcheck -f checkstyle \u0026gt; checkstyle-result.xml || : cloc --by-file --xml --out=cloc.xml . \u0026#39;\u0026#39;\u0026#39; } } stage (\u0026#39;集計\u0026#39;) { steps { sloccountPublish encoding: \u0026#39;\u0026#39;, ignoreBuildFailure: true, pattern: \u0026#39;cloc.xml\u0026#39; recordIssues(tools: [checkStyle()]) } } } } Jenkins の結果 下記のようにグラフにて表示されます。ビルド数が少ないのでわかりづらいですが\u0026hellip;\u0026hellip;。実際はもっとたくさんあるのでちゃんとしたグラフになります。\nステップ数はグラフだけでなく例えば下記のように言語ごとに表示することも可能です。\n件数の推移だけでなく深刻度におうじた円グラフなんかも表示されます。\nさらに指摘箇所は下記のようにコード中に表示されるのでとてもわかりやすい。\nこんな感じにいい感じにシェルスクリプトの状況が見える化できて素敵だと個人的には思っています。\nまとめ シェルスクリプトの静的解析ツールの ShellCheck とコードステップ数計測ツールを Jenkins で実行する方法でした。 サンプルのJenkinsfileも書いているのですぐにでも実践できるかなと思います！ぜひお試しください！\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-shell-analysis-pipeline/","summary":"\u003cp\u003eちょっとした作業ならシェルスクリプトで行うことも多いと思いますが大きくなるとメンテナンスが大変です。\nそこで Jenkins にて静的解析ツールとステップ数計測ツールを実行する方法を説明します。\u003c/p\u003e","title":"シェルスクリプトの静的解析とステップ数をJenkinsで監視 | ShellCheck と Cloc"},{"content":"ソースコードのステップ数を計測する便利ツール cloc を紹介します。\n本邦の伝統的な企業、いわゆるJTCにてプログラミングに従事していると、お客さんや偉い人から「ステップ数を出せ！」と言われることありますよね。 いまどきステップ数（LOC）がいったい何の役にたつのか不明ではありますが、積極的にケンカを売ってもいいことないのでささっと数えて終わらせたいところです。 目視で数えると日が暮れてしまうのでツールを使うわけですが、Windowsならかぞえチャオ！というソフトが有名ですね。\nこれでももちろんいいですのが Windows だけでなくLinux や Macでもつかえる便利ツール cloc を今回は紹介したいと思います。\nインストール Linux や WSL ならパッケージマネージャ経由でインストールするのが楽だと思います。例えばUbuntu なら下記のようにすればOKです。\n1 sudo apt install cloc Windows なら exeファイルをダウンロードするのが楽だと思います。 GitHub - AlDanial/cloc/releasesのところに各バージョンの実行可能ファイル（.exe）が置いてあるのでダウンロードします。Mac なら HomeBrew でインストールできます。\n基本的な使い方 基本的な使い方は引数でファイルもしくはディレクトリを指定するだけです。 下記では例としてccacheというソフトのコードのステップ数を調べています。 各言語ごとにステップ数が集計されて表示されます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $ git clone https://github.com/ccache/ccache.git $ cd ccache $ cloc . 366 text files. 365 unique files. 21 files ignored. github.com/AlDanial/cloc v 1.82 T=0.47 s (736.4 files/s, 253444.8 lines/s) -------------------------------------------------------------------------------- Language files blank comment code -------------------------------------------------------------------------------- Assembly 12 106 82 26265 C/C++ Header 104 5536 6578 25049 C++ 99 4069 3139 23322 Bourne Again Shell 47 1731 676 6615 C 16 559 607 5696 AsciiDoc 4 1675 0 3829 CMake 27 186 164 1113 Python 6 107 46 607 YAML 4 65 17 364 Markdown 9 84 0 271 Bourne Shell 8 51 28 201 Dockerfile 9 16 8 167 CSS 1 9 3 38 -------------------------------------------------------------------------------- SUM: 346 14194 11348 93537 -------------------------------------------------------------------------------- もし Excel などで集計したい場合は \u0026ndash;csv オプションが便利です。下記のように CSV で出力してくれます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ cloc --csv . 366 text files. 365 unique files. 21 files ignored. files,language,blank,comment,code,\u0026#34;github.com/AlDanial/cloc v 1.82 T=0.50 s (694.0 files/s, 238861.7 lines/s)\u0026#34; 12,Assembly,106,82,26265 104,C/C++ Header,5536,6578,25049 99,C++,4069,3139,23322 47,Bourne Again Shell,1731,676,6615 16,C,559,607,5696 4,AsciiDoc,1675,0,3829 27,CMake,186,164,1113 6,Python,107,46,607 4,YAML,65,17,364 9,Markdown,84,0,271 8,Bourne Shell,51,28,201 9,Dockerfile,16,8,167 1,CSS,9,3,38 346,SUM,14194,11348,93537 もしファイルごとに結果が欲しい場合は \u0026ndash;by-file オプションを使います。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 $ cloc --by-file . 366 text files. 365 unique files. 21 files ignored. github.com/AlDanial/cloc v 1.82 T=0.49 s (711.5 files/s, 244884.5 lines/s) ----------------------------------------------------------------------------------------------------------------- File blank comment code ----------------------------------------------------------------------------------------------------------------- ./src/third_party/doctest.h 1030 559 5227 ./src/third_party/httplib.cpp 936 376 5011 ./src/third_party/xxhash.h 552 2222 2806 ./src/third_party/blake3/blake3_avx512_x86-64_windows_msvc.asm 8 10 2616 ./src/third_party/blake3/blake3_avx512_x86-64_windows_gnu.S 8 0 2607 ./src/third_party/blake3/blake3_avx512_x86-64_unix.S 7 16 2562 ./src/third_party/fmt/core.h 419 334 2483 ./src/third_party/fmt/format.h 339 347 2418 ./src/third_party/blake3/blake3_sse2_x86-64_windows_msvc.asm 17 4 2329 ./src/third_party/blake3/blake3_sse2_x86-64_windows_gnu.S 5 0 2327 ./src/third_party/blake3/blake3_sse2_x86-64_unix.S 7 16 2268 ./src/third_party/fmt/format-inl.h 200 210 2233 ./src/third_party/blake3/blake3_sse41_x86-64_windows_msvc.asm 19 4 2066 ./src/third_party/blake3/blake3_sse41_x86-64_windows_gnu.S 5 0 2064 ./src/third_party/blake3/blake3_sse41_x86-64_unix.S 7 16 2005 ./src/third_party/nonstd/expected.hpp 484 175 1833 ./src/third_party/blake3/blake3_avx2_x86-64_windows_gnu.S 2 0 1815 ./src/third_party/blake3/blake3_avx2_x86-64_windows_msvc.asm 15 0 1813 ./src/third_party/blake3/blake3_avx2_x86-64_unix.S 6 16 1793 ./src/ccache.cpp 271 346 1746 ./doc/NEWS.adoc 1085 0 1560 ./doc/MANUAL.adoc 410 0 1458 以下略 これだけでも充分使えますがほかにも機能が盛り沢山です。 やりたいことはたいていあるのでcloc --help で調べてみてください。\nGit との連携 cloc のいろんな機能でとくにおすすめなのがGitとの連携です。\nある時点でのステップ数を計測 引数に Git コミットID を渡すことでその時点でのステップ数を計測してくれます。下記の例は最初のコミット時点でのステップ数です。渡すのはコミットIDでなくタグ名でもかまいません。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $ git log | tail -n10 Date: Tue Mar 26 16:11:48 2002 +0100 - use subdirs - better status handling commit f42859a15c39f0efd28382e7e7031895247cc085 Author: Andrew Tridgell \u0026amp;lttridge@samba.org\u0026gt; Date: Tue Mar 26 15:46:43 2002 +0100 first version of C compilercache $ cloc --git f42859a15c39f0efd28382e7e7031895247cc085 10 text files. 10 unique files. 0 files ignored. github.com/AlDanial/cloc v 1.82 T=0.02 s (496.8 files/s, 44858.6 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- C 7 162 62 578 C/C++ Header 2 26 17 47 make 1 3 0 8 ------------------------------------------------------------------------------- SUM: 10 191 79 633 ------------------------------------------------------------------------------- 変更差分のステップ数を計測 修正差分のステップ数も簡単に計測できます。 オプション --diffを使用します。 下記の例では最新のコミットの差分を計測しています。下記のようにHEADや HEAD^ も指定できます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ cloc --git --diff HEAD^ HEAD 1 text file. 1 text file. 0 files ignored. github.com/AlDanial/cloc v 1.82 T=0.07 s (14.9 files/s, 14.9 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- AsciiDoc same 0 0 0 1558 modified 1 0 0 2 added 0 0 0 0 removed 0 0 0 0 ------------------------------------------------------------------------------- SUM: same 0 0 0 1558 modified 1 0 0 2 added 0 0 0 0 removed 0 0 0 0 ------------------------------------------------------------------------------- Jenkins との連携 上記の使い方でも充分便利ですが、Jenkinsと組み合わせればコード量の推移をグラフにして可視化できます。 Jenkinsのプラグイン SLOCCount を使えば簡単です。 XML形式で計測結果を出力してそれをSLOCCount に渡せばいいだけです。 詳細はSLOCCountのサイトを参照してください。\nまとめ 今回は Linux, Windows, Mac で使えるステップ数計測ツール clocの紹介でした。 単純な計測だけでなく Gitと連携できることがすごいと思います。 さらに XML 形式で出力すれば Jenkinsでコード量の推移を監視できます。ほかにもいろんな使い方があると思うのでいろいろためしてみてください！\n","permalink":"https://nagayasu-shinya.github.io/posts/code-line-counter-cloc/","summary":"\u003cp\u003eソースコードのステップ数を計測する便利ツール cloc を紹介します。\u003c/p\u003e","title":"コードのステップ数計測ツール cloc"},{"content":"Linux の zipコマンドはよく使われるコマンドであり、さまざまなオプションがあります。その中でファイルのバックアップに便利そうなオプションを今回は紹介します。\n基本的な使い方 まず zip のおさらいです。基本的な使い方は簡単です。引数に作成する zipファイル名と圧縮するファイル名を渡せばOKです。 たとえば下記のようなファイルとディレクトリがあったとします。これを全部 zip にかためてバックアップを取ることを考えます。\n1 2 3 4 5 6 7 8 $ tree . ├── a.txt ├── b.txt ├── c.txt └── foo ├── fuga.txt └── hoge.txt ここでカレントディレクトリ以下全部を圧縮してみます。下記のように-r（--recurse-paths）の再帰オプションとワイルドカードを組み合わせればできます。 また、unzip -lは zipの中のファイル一覧を表示するコマンドです。期待通り全部格納されています。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ zip -r backup.zip ./* adding: a.txt (stored 0%) adding: b.txt (stored 0%) adding: c.txt (stored 0%) adding: foo/ (stored 0%) adding: foo/hoge.txt (stored 0%) adding: foo/fuga.txt (stored 0%) $ unzip -l Archive: backup.zip Length Date Time Name --------- ---------- ----- ---- 0 2022-02-24 23:24 a.txt 0 2022-02-24 23:24 b.txt 0 2022-02-24 23:24 c.txt 0 2022-02-24 23:25 foo/ 0 2022-02-24 23:24 foo/hoge.txt 0 2022-02-24 23:25 foo/fuga.txt --------- ------- 0 6 files 変更されたファイルだけ更新する つぎにファイルが変更されたときのことを考えます。 ファイルが変更されたらbackup.zip も作り直す必要がありますね。 いったん backup.zip を消して再度zipしてもいいのですが、 もしファイルが多かったり大きかったりするとその方法では効率が悪いです。\nそこで登場するのが -u （--update）オプションです。-uをつけると、変更されたファイルだけを更新できます。 下記の例では a.txtを変更し、 -u オプションをつけることで zip 内の a.txtだけを更新しています。 このとき変更されていない他のファイルは更新されません。これで不要な処理を省けます。 大量のファイルのバックアップを取るときはこのオプションが便利です。\n1 2 3 4 $ zip -r -u backup.zip ./* # backup.zip はなにも更新されない $ touch a.txt $ zip -r -u backup.zip ./* # a.txt が更新されたので backup.zip の a.txt も更新される updating: a.txt (stored 0%) 削除されたファイルを反映する 上記の -uオプションはファイルを変更したり新規に追加したりした場合は期待通り動作します。 しかしファイルが削除された場合には zip を更新しません。 たとえとして、ここでは a.txt を不要になったとしてファイルを削除した場合を考えてみます。\nこの状態で上述の -u オプションを使っても backup.zip からは a.txt は削除されません。 つまりファイルの状態と zip 内の状態が不一致になってしまいます。 backup.zip からも削除したい場合は-d（--delete）オプションを使うことで backup.zip 内からファイルを削除できます。\nですがこの場合はいちいち削除されたファイルを指定する必要があり、ファイル数が多い場合には漏れが出るかもしれません。 そこで今回は --filesyncオプションを使います。 これは名前の通り自動的にファイルの状態を同期してくれます。 a.txtが削除された状態で --filesync を使うと backup.zip から自動で a.txtを削除してくれます。\n下記の例には書いていませんが、ファイル更新があればもちろん -uと同じように zip 内のファイルも更新します。 バックアップを取るという目的ならこちらのほうが便利かと思います。\n1 2 3 4 $ rm -r a.txt $ zip -r -u backup.zip ./* # a.txt が削除されても test.zip はなにも更新されない $ zip -r --filesync backup.zip ./* # a.txt が削除されているので backup.zip からも a.txt が削除される deleting: a.txt zipのなかにディレクトリを作りたくない場合 オプション -r でサブディレクトリごと圧縮した場合は、ディレクトリ構成を保持したまま圧縮されます。 下記の例では foo ディレクトリごと圧縮されています。\n1 2 3 4 5 6 7 8 9 10 $ zipinfo backup.zip Archive: backup.zip Zip file size: 876 bytes, number of entries: 6 -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:43 a.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:31 b.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:31 c.txt drwxr-xr-x 3.0 unx 0 bx stor 25-Jun-12 10:32 foo/ -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:32 foo/fuga.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:32 foo/hoge.txt 6 files, 0 bytes uncompressed, 0 bytes compressed: 0.0% もしディレクトリを含めたくない、サブディレクトリ以下のファイル含めてすべてのファイルがトップにある状態で圧縮したい場合は \u0026ndash;junk-paths オプションが有用です。 下記の例では　\u0026ndash;junk-pathsを使って圧縮した場合、 fooディレクトリ自体は含まれず、そのfooディレクトリの下にあったfuga.txt, hoge.txtが含まれています。\n1 2 3 4 5 6 7 8 9 10 $ zip --junk-paths -r --latest-time --must-match --filesync backup.zip ./ $ zipinfo backup.zip Archive: backup.zip Zip file size: 724 bytes, number of entries: 5 -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:43 a.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:31 b.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:31 c.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:32 fuga.txt -rw-r--r-- 3.0 unx 0 bx stor 25-Jun-12 10:32 hoge.txt 5 files, 0 bytes uncompressed, 0 bytes compressed: 0.0% うっかり意図しないファイルを圧縮するのを防ぐ zipコマンドに存在しないファイルを指定してもエラーにはなりません。 Warningが出るのみです。うっかりファイル名を間違えてもエラーにならないので少し危ないです。\n1 2 3 $ zip -r --filesync backup.zip ./ none.txt zip warning: name not matched: none.txt Archive is current あらかじめファイル名がわかっているときは --must-matchオプションが有用です。 指定したファイルが見当たらないときはWarningではなくエラーにしてくれます。\n1 2 3 4 5 $ zip -r --must-match --filesync backup.zip ./ none.txt zip warning: name not matched: none.txt zip I/O error: No such file or directory zip error: File not found or no read permission (none.txt) /code\u0026gt; ワイルドカードを使う場合はもちろん効果が弱まるのでご注意を。\nまとめ 今回はファイルバックアップに便利な zip の --filesyncオプションを紹介しました。 ググってもこのオプションはあんまりヒットしないようなので、詳細はman zip で確認するのがいいかと思います。\n","permalink":"https://nagayasu-shinya.github.io/posts/zip-backup-efficient/","summary":"\u003cp\u003eLinux の \u003ccode\u003ezip\u003c/code\u003eコマンドはよく使われるコマンドであり、さまざまなオプションがあります。その中でファイルのバックアップに便利そうなオプションを今回は紹介します。\u003c/p\u003e","title":"zip コマンドで効率的にバックアップ"},{"content":"find コマンドを使うときに、.gitのようなディレクトリは検索対象に入れたくないです。 そこで特定のディレクトリを対象から外す方法を説明します。\n普通のfindの使い方 カレントディレクトリ以下のすべてのファイルを検索するなら下記のようにしますね。\n1 2 3 4 $ find ./ -type f ./foo/hoge.txt ./bar/fuga.txt ./bar/piyo.txt ディレクトリを検索したいなら下記の通り。\n1 2 3 $ find ./ -type d ./foo ./bar すごく便利なんですが、git のワークツリーで実行した場合にすこし困ったことになります。 Gitの管理ディレクトリである .git まで検索してしまいます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ git clone https://github.com/nagayasu-shinya/gnu-make-framework-zen.git $ cd gnu-make-framework-zen.git $ find ./ -type f ./LICENSE.txt ./README.md ./.git/hooks/pre-push.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-receive.sample ./.git/hooks/applypatch-msg.sample ./.git/hooks/update.sample ./.git/hooks/post-update.sample ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/pre-commit.sample # 略.... .git ディレクトリは管理ファイルの場所なので通常は直接触ることはないと思います。 そこで find で .git を除外する方法を説明します。\n-path オプションと -prune オプション 探索パスを指定するオプション -path と、真を返したうえでディレクトリの中へ入っていかないようにする -prune オプションを使います。下記のようになります。.git が含まれていません。期待通りの挙動ですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ find . -path ./.git -prune -o -type f -print ./LICENSE.txt ./README.md ./README_jp.md ./GNUmakefile ./build/create_executable.mk ./build/create_library.mk ./build/define_suffix_rule.mk ./build/define_macro.mk ./build/set_toolchain.mk ./build/clean_all.mk ./build/clear_local_variable.mk # 略 上記のコマンドを少しわかりやすくしてみました。区切りがわかりやすいようにカッコで囲みました。あと -o を -or にしました、同じ意味です。\n1 find . \\( -path ./.git -prune \\) -or \\( -type f -print \\) まず最初のカッコの中を見てみます。これは「パス ./.gitの中を除外する」という意味です。 -prune が除外するという意味です。 man の説明では \u0026ldquo;do not descend into it\u0026rdquo; となっていました。 またこの prune が実行されたとき（除外したとき）は真を返します。\nつぎは -orです。論理和なので、C言語などと同様に左の式が真ならその時点で真が確定するので、右の式は実行されません。 先程述べたようにprune は除外した場合は真を返すので .git 以下は pruneによって除外され真を返します。 そのためその時点で真が確定するので右の式は実行されません。\n一方pruneで除外されなかった場合は左の式が偽になるので右の式が評価されます。 結局、pruneで除外されなかったファイルだけが右の式にてファイル名表示されます。 これで期待の結果が得られます。\n右の -print は必要なの？ さきほど見た下記のコマンドですが、ぱっと見、一番右の -print は必要ないように見えます。\n1 find . -path ./.git -prune -o -type f -print しかし -print を削除すると下記のように除外しようとした .gitディレクトリが表示されてしまいます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ find . -path ./.git -prune -o -type f ./LICENSE.txt ./README.md ./.git ★ ← なぜか表示される！！！ ./README_jp.md ./GNUmakefile ./build/create_executable.mk ./build/create_library.mk ./build/define_suffix_rule.mk ./build/define_macro.mk ./build/set_toolchain.mk ./build/clean_all.mk # 略 この理由は man ページに記載がありました。 式 EXPRESSION の章に「-prune や -quit 以外のアクションが存在しない限り、式全体の結果が真になったすべてのファイルに対して -print が実行される」と記載があります。 先程のコマンド例の場合-path や -type はアクションではないので 「-prune や -quit以外のアクションが存在しない」ことになり、真となったファイルすべてに -print が実行されることになります。\nここで思い出してほしいのは「pruneは真を返す」ということです。 つまりprune で除外された .gitも真となるので、結局 .git も表示されてしまうわけです。 これを回避するためには「-prune や -quit以外のアクションが存在」すればいいので、 明示的に -print をつけているわけですね。\nまとめ 今回は find で検索するときに .gitディレクトリを除外する方法を説明しました。 オプションの -path と -prune さらに -printを使えば実現できます。 これをベースにいろいろ複雑な処理にも拡張できると思います。\n","permalink":"https://nagayasu-shinya.github.io/posts/find-command-exclude-gitdir/","summary":"\u003cp\u003e\u003ccode\u003efind\u003c/code\u003e コマンドを使うときに、\u003ccode\u003e.git\u003c/code\u003eのようなディレクトリは検索対象に入れたくないです。\nそこで特定のディレクトリを対象から外す方法を説明します。\u003c/p\u003e","title":".git を除外して find でファイルやディレクトリを検索する"},{"content":"ケンジントンのトラックボールを使っていたのですが、左クリックが効かなくなってしまいました。 修理してみたのでその方法を書いてみます。\nケンジントンのトラックボールを使っていたのですが、左クリックが効かなくなってしまいました。 ケンジントンは5年保証なのですがそれも過ぎてしまっておりダメ元で修理してみました。 結果うまく治ったので、その方法をかいておきます。何かの参考になれば。 ちなみにSlimBlade という製品で、いまでも13000円くらいします……。 直らなかったら泣いちゃうとこでした。 ちなみに SlimBlade というのは下記の製品です。\nリンク 修理に必要なものを調達する 今回の修理の内容は、スイッチに接点復活剤をかけてみて回復することを祈るというものです。 部品交換などはしなかったのでそれほど道具は必要ありません。\n精密ドライバ 分解するのに必須です。100均のものでも大丈夫です。ただ結構ネジが硬いので腕力がいります。 最近は下記のようないろいろな種類がセットになっているのもありますね。お好きなものをご利用ください。\nリンク 接点復活剤 電子部品の接触をよくするものです。今回は効かなくなったスイッチにかけました。 いろんな種類があるようですが私は下記のものを使いました。556でお馴染みの呉工業のやつですね。\nリンク 接着剤 分解するのに裏のゴム足などを剥がします。あとでそれをつけるために接着剤が必要です。 そんなに接着力は必要ないので何でもいいのですが、私は下記のゴム用接着剤を使いました。 アロンアルファなどの瞬間接着剤は固くなってしまい柔らかいゴムとなじまないので避けたほうがいいかもです。\nリンク シール剥がし 分解するときに裏のゴムを剥がしますが、そのときに使用します。普通のシール剥がしで問題ないと思います。 わたしはZippoオイルで代用しました。昔は家電量販店でもシール跡剥がしに使ってました。\nリンク 分解して修理 道具がそろえばあとは意外と簡単です。 まずトラックボールを裏返します。すると四隅にゴム足、真ん中に丸いゴムがあります。 この中にネジが隠れています。\nシール剥がしをつけながらゴムを剥がしていきます。はがしたゴムはあとで元に戻すのでなくさないように。\nこれでネジが見えます。全部で7つです。これを外します。 ネジを剥がしたら、ぱかっと開けます。ちょっと硬いのでかるくドライバーでこじ開けました。 開けると緑の基板が見えると思います。この基板にもネジが3つあります。これも外します。\nネジを外したらゆっくりと基板を持ち上げます。白いフレキで筐体とつながっているので無理に引っ張らないでください。 すると黒いスイッチが見えます。\nあとはここに接点復活剤をスプレーします。割と多めにかけても大丈夫そうです。 そのあと少し時間を置いてから、PCに接続してスイッチが効くようになったか確認します。 まだ効かないようだったら、PCから外したうえで再度スプレーかけてみます。 私はこれで復活できました！\nあとは開けた順と逆順でネジを閉めます。 ネジを全部閉めたらゴム足と丸いゴムを接着剤でくっつけます。 万が一また開けるときのことを考えて、ネジには接着剤がつかないように気をつけてください。 これで作業は終わりです。\nまとめ 今回はKensingtonのSlimBladeのボタンを修理しました。 他の製品でも開けることさえできれば同じ要領で直せるかもしれません。 保証期間が過ぎている場合はダメ元でトライしてみてもいいと思います！ ちなみにですが、トラックボールでなくマウスだと下記がおすすめです。 高いけど何年も使うものですしね！\nリンク ","permalink":"https://nagayasu-shinya.github.io/posts/slimblade-repair-guide/","summary":"\u003cp\u003eケンジントンのトラックボールを使っていたのですが、左クリックが効かなくなってしまいました。\n修理してみたのでその方法を書いてみます。\u003c/p\u003e","title":"Kensington SlimBlade を自分で修理"},{"content":"DeepLというAIによる翻訳サイトが流行っていますが、Emacs から直接翻訳する方法を説明します。\nDeepL というAIによる翻訳サイトが流行っていますね。Google翻訳よりも自然な訳をしてくれると話題です。使い方としてはサイトにてコピー＆ペーストするだけなのですが、Emacs 使いとしては Emacs から直接翻訳したいですよね。そこで今回はその設定方法について説明します。\nEmacs 前準備 今回使用するパッケージにあわせて前準備が必要です。すでに対応済みの場合はスキップしてください。\nMELPAの設定 つぎにMELPAを登録しておきます。下記のように init.el で設定しておけばよいかと思います。\n1 2 3 4 5 (package-initialize) (setq package-archives \u0026#39;((\u0026#34;gnu\u0026#34; . \u0026#34;https://elpa.gnu.org/packages/\u0026#34;) (\u0026#34;melpa\u0026#34; . \u0026#34;https://melpa.org/packages/\u0026#34;) (\u0026#34;org\u0026#34; . \u0026#34;https://orgmode.org/elpa/\u0026#34;))) DeepL APIの認証キーの取得 Emacs から DeepL を使用するには APIを利用します。APIを使うには認証キーが必要です。\nまずはDeepLの公式サイトにアクセスします。 サイトの上の方に「API」と書いてあるところがあるのでそこをクリックしてください。下図の赤枠のところです。\n次に、下の方に「無料で登録する」というところがあるのでそこをクリック。下図の赤枠のところです。\nすると名前や住所、クレジットカード情報を聞かれます。 「クレジットカードの入力は1人で複数登録するのを防ぐため（意訳）」と書いてあります。 フリープランなら課金されることはないので問題ないでしょう。そのまま進め登録を完了させます。\nこれでAPI認証キーを取得する準備ができました。右上のほうのアカウント名をアカウント情報を表示させます。 アカウントタブのところをクリックすれば下記のようにAPI認証キーが表示されるはずです。あとでこれを入力する必要がありますのでどこかにメモしておいてください。\ngo-translate のインストール Emacsパッケージの go-translate をインストールします。 MELPA からダウンロードできます。下記のコマンドでインストールできます。\n1 M-x package-install RET go-translate RET GUIでインストールしてもOKです。下記のような感じですね。\nちなみにパッケージのGitHubは Emacs go-translate です。\ngo-translate の設定 init.el に下記のように記載すればOKです。 auth-keyのところのXXXXXは前述したDeepLのAPI認証キーを設定してください。 これで設定は終わりです。下記の例ではC-c tに翻訳機能を割り当てています。 翻訳したい文章をリージョン選択してC-c tを入力すると翻訳されるはずです！\nNote\n2025-07-26追記。 いつのまにかgo-translatorパッケージに互換性のない修正が入っていてサンプルコードが動かなくなっていましたので書き直しました。\n1 2 3 4 5 6 7 8 9 10 11 12 (require \u0026#39;go-translate) ;; 翻訳設定 (use-package go-translate :if (boundp \u0026#39;private-deepl-auth-key) ; DeepLキーが定義されている場合のみ有効化 :bind (\u0026#34;C-c t\u0026#34; . gt-do-translate) :config (setq gt-langs \u0026#39;(ja en) ) (setq gt-default-translator (gt-translator :engines (gt-deepl-engine :key \u0026#34;XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX:XX\u0026#34;) :render (gt-buffer-render)))) C-c t で下記のようになればOKです！\nちなみにコメントアウトしている箇所を変更するとGoogle翻訳を有効にしたり、 翻訳結果をキルリングに入れたりすることもできます！いろいろ試してみてください。\nまとめ 今回は DeepL をEmacsから直接使う方法を紹介しました。 ブラウザにコピペする手間が省けて便利だと思います！\n","permalink":"https://nagayasu-shinya.github.io/posts/emacs-deepl-translator-integration/","summary":"\u003cp\u003e\u003ca href=\"https://www.deepl.com/translator\"\u003eDeepL\u003c/a\u003eというAIによる翻訳サイトが流行っていますが、Emacs から直接翻訳する方法を説明します。\u003c/p\u003e","title":"Emacs から直接 DeepL を使う設定方法"},{"content":"職場のPCはリース契約のことも多く定期的に入れ替えが発生することが多いです。 そこでやっておいたほうがいいだろう Windows設定を紹介したいと思います。\nUbuntuなどのLinuxも最近は流行っていますが、職場でのメインマシンとしてはまだまだWindowsが大半だと思います。 また、職場のPCはリース契約のことも多く、定期的にPCを交換しなくてはいけないことも多いものです。 そこで今回は、ひとまずやっておくと良いと思われる Windows設定を紹介したいと思います。お好みに合ったものを設定してみていただければと思います。\nコントロールパネルの表示設定 設定はコントロールパネルから行うものが多いです。 このコントロールパネルの表示はデフォルトでは「カテゴリ」という設定になっており、すべての項目が表示されていません。そこで表示を「大きいアイコン」もしくは「小さいアイコン」に変更します。 これで表示される項目が増えるはずです。 下記ではこの表示設定をしていることを前提に説明します。\nエクスプローラ関係 Windowsで最も使うアプリケーションはエクスプローラかもしれません。この設定を変更して少しでも快適になるようにします。\nフォルダの表示設定 これは開発者に限らずほぼ全員が設定していると思いますが、念のためあげておきます。 デフォルトではなぜか拡張子が表示されないようになっているので、ちゃんと拡張子を表示するように設定します。 「コントロールパネル」→「エクスプローラーのオプション」と移動して、開いたウィンドウの「表示」タブを選択します。 そこで「登録されている拡張子は表示しない」のチェックボックスを外します。下記の図の赤枠のところです。\nまた合わせて隠しファイルも表示するようにしておきます。開発ツールなどの設定が置いてあるAppdData フォルダなど参照するためには必要な設定です。\n表示とパフォーマンス たとえばフォルダを最小化、最大化するときにはアニメーションで表示されるかと思います。 しかし実際にはそのような見栄えは必要ないので、それらを無効にします。\n「コントロールパネル」 → 「システム」 → 「詳細情報」 →「システムの詳細設定」と移動します。 開いたウィンドウのパフォーマンスのところの設定ボタンをクリックします。すると下記の図のような各効果の設定画面が表示されます。 基本的に無効で困らないと思います。 ただし「スクリーンフォントの縁を滑らかにする」だけは有効にしておいたほうがいいです。無効にすると文字がガタガタになってかなり読みづらくなります。\nクイックアクセス無効 Windows10では、よく使っているフォルダをWindowsが自動的にクイックアクセスというところにピン留めします。エクスプローラを開いたときに左側に表示されているはずです。 よく使うフォルダは明示的にピン留めすればよく、この機能は動作が重くなる原因にもなりますので無効化します。\n「コントロールパネル」→「エクスプローラーのオプション」と移動して、開いたウィンドウの「全般」タブを選択します。そこの「最近使ったファイルをクイックアクセスに表示する」と「よく使うフォルダーをクイックアクセスに表示する」のチェックを外します。下記の図を参照ください。\nタスクバー関係 基本的に常に表示されるタスクバーも快適性にとって重要です。自分に合うようにカスタマイズしましょう。\n不要な検索機能などを削除 タスクバーは、いろんなアプリケーションを立ち上げているとすぐにアイコンで溢れてしまいます。そのようにただでさえ狭いタスクバーに、デフォルトで不要な機能が表示されています。下の図の赤枠のところです。これを非表示にします。\nタスクバー上で右クリックし、それぞれ非表示にします。下図の赤枠のところを参照してください。\nアイコンを小さくする いろんなアプリケーションを立ち上げていると狭いタスクバーにはすぐにアイコンが溢れてしまいます。そこで少しでも多くのアイコンを表示できるように、アイコンを小さくします。 「コントロールパネル」 →「タスクバーとナビゲーション」と移動し、『小さいタスクバーボタンを使う」を有効にしてください。下記の図の赤枠のところです。\nタスクバーを横に配置する 通常のディスプレイは横長ため、横は余りがちで縦方向は逼迫しがちです。そこで、デフォルトでは下に配置されているタスクバーを横に移動させます。これにより1画面で表示できる行数もふえて多少みやすくなります。 タスクバー上で右クリックして「タスクバーを固定する」のチェックをはすします。次にタスクバーをドラッグして画面右端（もしくは左端）に移動させます。あとは幅の長さを調節して、最後に「タスクバーを固定する」にチェックを入れ直します。\nマウスとキーボード関係 マウスの設定も見直しておきましょう\nタッチパッドのタップを無効化 ノートPCではタッチパッドが搭載されているかと思います。 このタッチパッドですが、デフォルトではトンとタップするとマウスのクリックと同じ挙動になります。 この機能が有効だと、単にマウスカーソルを移動させようとタッチパッドをスーッとなぞったら、タッチパッドに触れたときにクリックしたと判断され、たまたまそこにあったフォルダをドラッグしてしまい、そのままフォルダを移動させてしまうことがあります。 そのためいつの間にかフォルダがどこか別のフォルダの中に移動されたりして、なかなか厄介なことになるときがあります。\n単にボタンでクリックすればいいだけなので、面倒ごとをと避けるためにタッチパッドのタップは無効にしておきましょう。タッチパッドの設定はメーカーごとに異なるのでググってみてください。メーカーによってはコントロールパネルでなく専用ツールが必要な場合もあります。\nマウスのいる場所をわかりやすくする マルチディスプレイ環境など大きな画面で作業していると、マウスカーソルがどこにいったかわからなくなるときがあります。 「コントロールパネル」→「マウス」と移動し開いたウィンドウの「ポインターオプション」タブを選択します。そして「Ctrlキーを押すとポインターの位置を表示する」にチェックを入れます。これでCtrlを押すとマウスの位置がわかるようになります。\nクリップボードの履歴設定 最近のWindowsにはクリップボードに複数のデータを保存できる機能があります。たとえば何回か前にコピーしたデータを呼び出してペーストできます。このクリップボードの履歴機能はデフォルトでは無効なので、有効化します。\n「コントロールパネル」 → 「システム」 →「クリップボード」と移動します。下記の図を参考のクリップボードの履歴を有効にします。 これで Win + v キーで履歴を呼び出せます。\n詳細は 【Windows10】「クリップボード履歴」を活用するも参考にしてみてください。\ncapslock を ctrlにする まず使うことのないCapsキーですが、一般的なキーボードではAの左横という一等地に配置されています。 これはもったいないので、CapsをCtrlに置き換えます。\nこれを実施するツールはたくさんありますが、ここではMicrosoft謹製のSysinternalsを紹介します。 サイトから zipファイルをダウンロードし、任意のところに解凍します。そのなかにctrl2cap.exeというものがあります。 コマンドプロンプトを管理者権限で開いて、下記のように実行すればOKです。次回起動時からcapslock が ctrl になります。\n1 \u0026gt; ctrl2cap /install 電源オプション PCと端末をつないでヒートランなど長時間テストをするときに必要と思われる設定を紹介します。ここではノートPCを想定しています。\nスリープ突入の無効化 長時間PCを放置してもスリープしてしまわないようにします。 「コントロールパネル」→「電源オプション」→「プラン設定の編集」と移動します。すると下記のように一定時間PCを触らなかっときにスリープに入れるかの設定ができます。 長時間テストをするときは電源につないでいると思うので下記のように設定すればよいでしょう。\nノートPCを閉じたときの挙動 ノートPCのカバーを閉じた状態でも処理を継続したい場合に設定します。 「コントロールパネル」→「電源オプション」→「カバーを閉じたときの動作」と移動します。下記の図を参考に設定します。 まとめ Windowsにてひとまずやっておいたほうがよいとおもう設定を紹介しました。好みの問題も多いので、取捨選択して活用いただければと思います。 また、Windowsマシンに入れておきたい定番開発ツールたちも書いています。こちらもぜひ。\n","permalink":"https://nagayasu-shinya.github.io/posts/windows-developer-setup/","summary":"\u003cp\u003e職場のPCはリース契約のことも多く定期的に入れ替えが発生することが多いです。\nそこでやっておいたほうがいいだろう Windows設定を紹介したいと思います。\u003c/p\u003e","title":"Windowsのおすすめ初期設定"},{"content":"C/C++のコンパイル高速化ツール ccache のキャッシュを複数ユーザーで共有してビルドを高速化する方法を説明します。\nccacheとは c/c++ のコンパイルを高速化するツールにccacheというものがあります。 コンパイル結果をキャッシングしておき次回以降のビルドを高速化するツールです。C/C++界隈ではメジャーなツールです。 Arduino のビルド高速化なんかにも使えたりします（下記の記事参照）\nArduinoでccacheを使ってビルドを高速化！ C/C\u0026#43;\u0026#43;のコンパイルを高速化する｜ccache 特定の機種をチームで開発するときは各人が同じコードをコンパイルしていることが多いと思います。 そこで今回は、ccacheがキャッシングした結果を複数ユーザーで共有することでみんなでccacheの恩恵にあずかろうという話です。 みんなでキャッシュを使うことでよりキャッシュヒットの効果がでやすくなるはずです。\nまた、ビルドといえばJenkinsを利用している方も多いと思いますが、 ユーザーと Jenkins とで ccacheの結果を共有するコツも合わせて記載します。 Jenkinsがキャッシュを共有することでつねにキャッシュが更新されるので他のユーザがより恩恵を預かりやすくなります。\n注意点ですが、ここでは同一マシンを使うユーザーを想定しています。リモートのマシン間での共有は想定していません。 リモート間での共有に興味がある方は distcc で検索してみてください。\n共用キャッシュディレクトリの作成 ccache はデフォルトの設定では各ユーザのホームディレクトリ配下の~/.ccache ディレクトリの下にキャッシュファイルを生成します。 しかしこれではユーザ間でキャッシュファイルを共有することができません。 そこでまず、みんながアクセスできるような場所にキャッシュを保存するディレクトリを作成します。\n場所はどこでもいいのですが SSDなどの高速なストレージ上がいいと思います。HDDは避けたほうがいいでしょう。 ここでは例として /mnt/ssd/.ccache/を共有キャッシュディレクトリにすることにします。 下記のように普通にディレクトリを作成します。\n1 2 cd /mnt/ssd/ mkdir .ccache/ 共用キャッシュディレクトリのアクセス権設定 つぎに、他のユーザも共用キャッシュディレクトリにアクセスできるようにします。 といっても、だれでもかれでもアクセスできるようにするわけには行かないので、 ここではグループを作成することにします。\nグループ名は何でもいいのですが、ここでは ccacheとしておきます。 そしてそのグループに ccache を使うユーザを追加します。 下記の例では username_1 username_2 というユーザを追加しています。\n1 2 3 groupadd ccache sudo adduser username_1 ccache sudo adduser username_2 ccache また、新規に作成されるディレクトリのために setgid もしておきます。\n1 2 chgrp ccache /mnt/ssd/.ccache/ chmod g+s /mnt/ssd/.ccache/ コンパイル時の環境変数設定 あとは環境変数にてキャッシュディレクトリの場所の設定を行います。またあわせて umask の設定も必要です。 下記のようにすればOKです。\n1 2 export CCACHE_DIR=/mnt/ssd/.ccache/ export CCACHE_UMASK=002 これで ccache を実行すれば /mnt/ssd/.ccache/ 以下にキャッシュファイルが出力され、かつ、 他のユーザもそれを利用することができるようになります。\nJenkins の場合の設定 せっかくなら常時ビルドを実行しているJenkinsともキャッシュを共用したいところです。 Jenkins ジョブはユーザー jenkins グループ jenkinsとして実行されるので、 ccache グループに jenkinsを追加すれば良さそうに思えます。 しかしそれでは下記のようなエラーが出てしまいます。\n1 ccache: error: Failed to create temporary file for /mnt/ssd/.ccache/tmp/tmp.cpp_stderr: Permission denied じつはJenkins ジョブのユーザーとグループは /etc/default/Jenkins ファイルにて設定されています。 なのでそのファイルを変更する必要があります。 まずは root 権限でエディタでファイルを開きます。\n1 sudo emacs /etc/default/Jenkins 下記のような設定箇所がありますので、 JENKINS_GROUP を ccacheに変更します。\n1 2 3 4 # user and group to be invoked as (default to jenkins) JENKINS_USER=$NAME #JENKINS_GROUP=$NAME JENKINS_GROUP=ccache あとは下記のように Jenkins をリスタートさせれば、Jenkinsも共用キャッシュを利用できるようになります。\n1 sudo service jenkins restart まとめ 今回は同一マシン上で ccache のキャッシュファイルを共有する方法を説明しました。 また、Jenkinsでもccache のキャッシュファイルを共有する方法も説明しました。 Jenkinsと組み合わせることで常にキャッシュが更新された状態にできますのでますますccacheを便利に使えると思います！\n","permalink":"https://nagayasu-shinya.github.io/posts/ccache-multi-user-sharing/","summary":"\u003cp\u003eC/C++のコンパイル高速化ツール \u003ccode\u003eccache\u003c/code\u003e のキャッシュを複数ユーザーで共有してビルドを高速化する方法を説明します。\u003c/p\u003e","title":"ccache のキャッシュファイルを複数ユーザやJenkinsと共有する"},{"content":"Windows 上で動くソフトウェア開発ではいろんなツールを紹介します。\nソフトウェア開発ではいろんなツールを使います。 そこで今回は、Windowsマシンにインストールしておいたほうがいいとおもうフリーソフトを列挙してみます。 おそらく他の開発者のひともインストールしていると期待してもそれほどおかしくないメジャーどころを集めてみました。 WSL上などCLIで動作するものまで挙げたらきりがないので、今回はGUIで動作するものに絞っています。\nTera Term 説明不要の定番ターミナルソフトです。とくに組み込み開発者はPCとターゲットとのシリアル（UART)接続でお世話になりますね。 公式サイトはここ → Tera Term。\n書籍としては下記の本が参考になるかと思います。\nリンク あと、ちょっとしたTipsをTera Term のデフォルト値を変更して便利に使うに書いていますのでよろしければ。\nWinMerge ファイル間の差分をわかりやすく表示してくれるツールです。ソースコードの比較などにもってこいです。マージも簡単にできます。 公式サイトはココ→WinMerge 日本語版\nWinSCP Linux などでのファイル転送には scpコマンドを使うかと思いますが、それをGUIで簡単にできるツールです。 サーバとのデータのやり取りなど楽になるのでこれもぜひ入れておきたいですね。 公式サイトはココ→WinSCP\nRelaxTools Addin 本邦の開発者には必須の開発ツール MS Excelですが、ご承知の通り使いづらいです（本業の表計算以外のことをさせると。当たり前ですが）。 そのストレスを大幅に軽減してくれる素敵なアドインがこれです。 ほんとうに多種多様な機能があるので公式サイトを確認してみてください。 公式サイトはココ→RelaxTools Addin\nExcelの素敵アドイン「RelaxTools Addin」でRedmineの表作成もカンタンに！もご参照ください。\n7-Zip ファイル圧縮、解凍ソフトです。これがあればひとまず困ることはないと思います。 7z形式の他に zipやtarなどにも対応しています。 また、ファイルのハッシュ値（SHA1など）も簡単に計算できます。とても便利。 公式サイトはココ→ 7-Zip\nSysinternals マイクロソフト謹製の便利ツールパッケージです。 無用の長物である CapsLock を Ctrl に変換するツール Ctrl2Cap や、 タスクマネージャの高機能版 Process Explorer などが同梱されています。 公式サイトはココ→Sysinternals\nPowerToys これもマイクロソフト謹製です。Sysinternalsと同じようにいろんな機能があります。一括ファイルリネームや画像サイズを手軽に変更したり、マウスのいちをわかりやすくしたり。 いろいろあるので細かいことはググってもらうほうが早いと思います。結構便利。 公式サイトはここ→PowerToys\nStirling バイナリエディタの定番ですね。ひとまずこれがあれば困らないでしょう。私の手元の環境ではWindows7 でも Windows10 でも問題なく動作しています。 Vectorのダウンロードサイトはココ →Stirling ダウンロード\ndiagrams.net （旧draw.io） UML や回路図など何でも対応できるすぐれもののドローツールです。以前は draw.io いう名前でしたが、いまはdiagrams.net という名前になっています。 もともとは Webアプリでした。ココからアクセスできます→diagrams.net\nRapture 画面キャプチャソフトです。マウスで選択した範囲をキャプチャしてくれます。 Windows標準にもSnipping Toolsというキャプチャソフトがありますが、 Raptureのほうが使い勝手はいいように思います。\nキャプチャした画面は付箋のように表示したまま（しかも他のWindowより全面にでる）ので、ノートPCのように狭い画面の場合に、ちょっとメモしておきたい場所をキャプチャしてそれを画面の橋に置いておく、という使い方を良くします。 ともかく一度触ってみてもらいたいツールです。 Vectorダウンロードサイトはココ→ Rapture\nScreenToGif 静止画は Snipping Tools や Rapture でいいのですが動画を撮りたいときはこのツールが便利です。パソコンの画面をGIF動画にしてくれます。操作方法などの説明資料を作るときに役立ちます！！ 公式サイトはココ→ ScreenToGif\nSikuliX GUIの自動化ツールです。「このアイコンをクリックして文字列を入力して……」などのような操作を簡単に自動化できます。Selenium のようなツールですが SikuliX はウェブブラウザにとどまらずなんでも操作対象にできます！また設定も簡単！押したボタンをキャプチャしてぺたぺたするだけ！ Java がすでにインストールされていれば JAR をダウンロードしてそれをダブルクリックするだけで使えます！ 公式サイトはココ→ SikuliX\nVisual Studio Code いまをときめくエディタですね。特に説明はふようですかね。初期状態でも十分使いやすいですが、拡張機能でもっと便利になります。 もはやデファクトスタンダードと言ってもいい勢いですね。 Visual Studio Code はココ→Visual Studio Code\nそんなはやりものには飛びつかないぞ！という気骨のある方はこちら →Emacs\nVLC media player 大抵のものは再生できるメディアプレーヤーです。Windows Media Playerで再生できなくてもこれなら再生できること多いです。 たまに不具合再現方法が動画で送られてきたりするのでそういうときに活躍します。 公式サイトはココ→VLC media player\nまとめ 今回はど定番のWindows向けソフトの紹介をしました。どれもこれも素敵なソフトですのでぜひ一度試してみてください！ また、Windowsのおすすめ初期設定にひとまず設定したほうがいい Windows設定を書いています。よろしかったら見てみてください！\n","permalink":"https://nagayasu-shinya.github.io/posts/windows-developer-tools/","summary":"\u003cp\u003eWindows 上で動くソフトウェア開発ではいろんなツールを紹介します。\u003c/p\u003e","title":"Windowsマシンに入れておきたい定番開発ツールたち"},{"content":"大規模なプロジェクトにて複数の Git リポジトリを扱う際はgoogle Repoを使用することがあります。 このRepoにてコードのダウンロードを高速化する方法を説明します。\nGoogle Repo とは 大規模なプロジェクトだと、複数の Git リポジトリが必要になってきます。 そのリポジトリを1つ1つ操作するのは大変なので、大規模プロジェクトでは Repo というツールを使うことが多いと思います。\nRepoは複数のGitリポジトリを効率的に扱うツールで、AOSP (Android Open Source Project)などで用いられています。 いろいろなところで使われている Repo ですが、たとえば AOSPはソースコードだけで250GBくらいあり、ダウンロードするだけでも時間がかかってしまいます。 そこで今回は Repo を使ったさいのコードのダウンロードの高速化について説明します。\nシャロークローン 通常の Git と同様に Repo を使ってもシャロークローンができます。 シャロークローンは最新のコミットのみをダウンロードします。最新のビルドをしたいなど、過去の履歴が必要ない場合に有効です。 シャロークローンについてはGitHubの公式ブログのパーシャルクローンとシャロークローンを活用しよう に詳しい説明があります。 Repo の init 時に --depth=DEPTHにてシャロークローンができます。通常は 1 を指定しておけばよいでしょう。\n1 repo init --depth=1 -u ssh://your-manifest.git -b manifest-branch -m manifest-name もし過去の履歴が必要になった場合はアンシャローします。過去の履歴が必要なリポジトリの場所に移動して下記を実行します。\n1 2 cd git-repository/ git fetch origin master --unshallow ミラーリング 前述のようにシンボリックリンクで直接projectファイルを共有することもできますが、 repo のミラー機能を使って同じようなことも可能です。 まず最初にミラーとなるソースツリーをダウンロードします。 --mirrorを付けてください。\n1 2 3 cd /path/to/mirror/ repo init --mirror -u ssh://your-manifest.git -b manifest-branch -m manifest-name repo sync 以降は、ミラーを参照するようにします。 --reference を使用してください\n1 2 repo init --reference=/path/to/mirror/ -u ssh://your-manifest.git -b manifest-branch -m manifest-name repo sync ジョブの並列化 ダウンロード時に -j オプションを付けると並列に実行できます。\n1 repo sync -j16 利用可能な CPU の数を確認するには、nproc \u0026ndash;all コマンドを実行します。下記のようにすると楽でしょう。\n1 repo sync -j$(nproc --all) フェッチするブランチを限定する 現在のブランチのみフェッチするようにすることでダウンロードを高速化できます。 -c オプションを使用します。\n1 repo sync -c まとめ 大規模プロジェクトを管理する Repo を使ってソースコードをダウンロードするときの高速化について説明しました。 下記の方法で高速にダウンロードできるかなと思います。Jenkins などの CI を回すさいなどに有効かと思います。\n","permalink":"https://nagayasu-shinya.github.io/posts/repo-sync-shallow-clone/","summary":"\u003cp\u003e大規模なプロジェクトにて複数の Git リポジトリを扱う際はgoogle \u003ca href=\"https://source.android.google.cn/setup/develop?hl=ja#repo\"\u003eRepo\u003c/a\u003eを使用することがあります。\nこのRepoにてコードのダウンロードを高速化する方法を説明します。\u003c/p\u003e","title":"Git-Repo を使ったソースコードのダウンロード高速化"},{"content":"Windows Explorerで作業していて、そのフォルダから直接コマンドプロンプトを起動したいときに便利な方法を説明します。\nフォルダをエクスプローラで開く まずはフォルダをエクスプローラで開きます。ここでは例としてDownloadフォルダを開いています。 アドレスバーに入力 ここでアドレスバー内をコピーして、コマンドプロンプトでcdで移動するのが一番愚直な方法ですね。 それでもいいのですが、例えばDownloadフォルダの場合は下記のようになりうまく行きません。 そこでアドレスバーに「cmd」と打ち込んで見てください すると下記のように、Downloadフォルダでコマンドプロンプトが開くはずです！ まとめ エクスプローラのアドレスバーにcmdと打ち込むとそのフォルダからコマンドプロンプトが開けます。 アドレスバーからコピペするより楽なのでぜひご活用ください！\n","permalink":"https://nagayasu-shinya.github.io/posts/windows-explorer-cmd-launcher/","summary":"\u003cp\u003eWindows Explorerで作業していて、そのフォルダから直接コマンドプロンプトを起動したいときに便利な方法を説明します。\u003c/p\u003e","title":"エクスプローラで開いているフォルダで一発でコマンドプロンプトを開く方法"},{"content":"C言語には列挙型 enum というものがあります。かなり便利な機能なのですが効果的に使われていることは少ないように思います。 そこで列挙型を正しく使うとどのようなご利益があるかを説明します。\nマジックナンバーを使った例 例題として、引数に応じて曜日を出力する関数を考えてみます。まずは良くない例として引数をマジックナンバー（直値）で指定する関数を挙げてみます。 動作はしますが、引数に唐突に数字が渡されるので可読性が低いです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int func(int day) { if (day == 0) puts(\u0026#34;Sunday.\u0026#34;); else if (day == 1) puts(\u0026#34;Monday.\u0026#34;); else if (day == 2) puts(\u0026#34;Tuesday.\u0026#34;); else if (day == 3) puts(\u0026#34;Wednesday.\u0026#34;); else if (day == 4) puts(\u0026#34;Thursday.\u0026#34;); else if (day == 5) puts(\u0026#34;Friday.\u0026#34;); else if (day == 6) puts(\u0026#34;Saturday.\u0026#34;); return 0; } int main(void) { func(0); func(1); func(2); func(3); func(4); func(5); func(6); return 0; } マクロを使った例 マジックナンバーを使うのはよろしくないと、一度は言われたことがあると思います。 そこで曜日を数値でなくマクロにしてみました。少しは可読性がよくなりました。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #define SUNDAY (0) #define MONDAY (1) #define TUESDAY (2) #define WEDNESDAY (3) #define THURSDAY (4) #define FRIDAY (5) #define SATURDAY (6) int func(int day) { if (day == SUNDAY) puts(\u0026#34;Sunday.\u0026#34;); else if (day == MONDAY) puts(\u0026#34;Monday.\u0026#34;); else if (day == TUESDAY) puts(\u0026#34;Tuesday.\u0026#34;); else if (day == WEDNESDAY) puts(\u0026#34;Wednesday.\u0026#34;); else if (day == THURSDAY) puts(\u0026#34;Thursday.\u0026#34;); else if (day == FRIDAY) puts(\u0026#34;Friday.\u0026#34;); else if (day == SATURDAY) puts(\u0026#34;Saturday.\u0026#34;); return 0; } int main(void) { func(SUNDAY); func(MONDAY); func(TUESDAY); func(WEDNESDAY); func(THURSDAY); func(FRIDAY); func(SATURDAY); return 0; } 列挙型を使う こんどはマクロの代わりに列挙型を使ってみました。可読性はマクロと同等ですね。列挙型にメリットはあるのでしょうか。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 typedef enum { sunday, monday, tuesday, wednesday, thursday, friday, saturday, } day_t; int func(day_t day) { if (day == sunday) puts(\u0026#34;Sunday.\u0026#34;); else if (day == monday) puts(\u0026#34;Monday.\u0026#34;); else if (day == tuesday) puts(\u0026#34;Tuesday.\u0026#34;); else if (day == wednesday) puts(\u0026#34;Wednesday.\u0026#34;); else if (day == thursday) puts(\u0026#34;Thursday.\u0026#34;); else if (day == friday) puts(\u0026#34;Friday.\u0026#34;); else if (day == saturday) puts(\u0026#34;Saturday.\u0026#34;); return 0; } int main(void) { func(sunday); func(monday); func(tuesday); func(wednesday); func(thursday); func(friday); func(saturday); return 0; } 列挙型は列挙子に勝手に数値を割り当ててくれるので、その手間が省けるというのはあります。 上記だとsundayから０から６まで割り当てられます。しかし、ほんとうのメリットはそこではありません。\n関数の引数がint型から列挙型day_tに変更されています。 これがポイントです。int型なら0でも100でも1000でも渡すことができてしまいます。 関数に引数チェックを追加すれば実行時にそのような期待しない数値をはじくことはできますが、それはかなり遅いタイミングでのエラー回避です。 エラーを検出するのははやければ早いほど手戻りが減るので嬉しいです。 列挙型 day_t の場合はsundayからsaturdayの７個しか値がないので、不正な値をわたすことがそもそもできません。 正確にはやろうとおもえばできますが、コンパイル時に型の不一致で警告なりが出されます。つまり実際に動かす前に不正な引数をチェックできます。これが列挙型のメリットです。\nおまけ 上記の例では処理とデータの分離ができていません。データはデータ、処理は処理にわけておかないとメンテが大変です。 下の例ではデータは配列としてまとめてみました。処理はputs一行になりました。 列挙子を配列の添字に使うことには賛否あるかと思いますが、例として挙げておきます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 typedef enum { sunday, monday, tuesday, wednesday, thursday, friday, saturday, } day_t; int func(day_t day) { const static char *s[] = { \u0026#34;Sunday\u0026#34;, \u0026#34;Monday\u0026#34;, \u0026#34;Tuesday\u0026#34;, \u0026#34;Wednesday\u0026#34;, \u0026#34;Thursday\u0026#34;, \u0026#34;Friday\u0026#34;, \u0026#34;Saturday\u0026#34;, }; puts(s[(int) day]); return 0; } int main(void) { func(sunday); func(monday); func(tuesday); func(wednesday); func(thursday); func(friday); func(saturday); return 0; } まとめ 今回は列挙型をつかうことのメリットの一例を挙げました。関数の引数を列挙型にすることで、不正な引数をコンパイル時に検出でき手戻りを削減できます。ぜひ列挙型を使っていきましょう。\n","permalink":"https://nagayasu-shinya.github.io/posts/c-enum-usage-guide/","summary":"\u003cp\u003eC言語には列挙型 \u003ccode\u003eenum\u003c/code\u003e というものがあります。かなり便利な機能なのですが効果的に使われていることは少ないように思います。\nそこで列挙型を正しく使うとどのようなご利益があるかを説明します。\u003c/p\u003e","title":"C言語の列挙型の真面目な使い方"},{"content":"組み込みソフト開発でよく使われているTera Termのデフォルト設定値の変更方法を説明します。\n背景 WindowsをホストPCとして使う場合に、ターゲットとのシリアル接続（UARTなど）にはTera Termを使うことが多いと思います。 このTera Termですが設定ファイルを修正することでいろんなデフォルト値を修正できます。 今回はボーレート（通信速度）と通信先（TCP/IP or シリアル）のデフォルト設定の変更方法を紹介します。 これにより、Tera Term起動時に毎回手動で設定していたものを自動化できます。\nボーレートのデフォルト値の設定 通常 Tera Termはデフォルトではボーレート（通信速度）は9600になっています。ですが、大抵の機器では115200に設定することが多いと思います（下図参照）。 機器を接続しなおすたびにこの設定をするのはめんどくさいです。そこで、このデフォルト値を変更して、手作業でボーレートを設定する手間を減らしたいと思います。\n設定ファイル TERATERM.INI Tera Termのデフォルト設定は TERATERM.INIファイルに記載されています。このファイルは通常インストールフォルダに格納されています。 デフォルトではC:\\Program Files(x86)\\teraterm\\TERATERM.INIにあります。 ボーレートの設定はこのファイルの310行目あたりにあります。 シリアル接続設定がまとめてあり、その中に「BaudRate」というパラメータがあるはずです。私の手元の環境では下記のようになっていました。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; Serial port parameters ; Port number ComPort=1 ; Baud rate BaudRate=9600 ; Parity (even/odd/none/mark/space) Parity=none ; Data (7/8) DataBit=8 ; Stop (1/1.5/2) StopBit=1 ; Flow control (x/hard/none) FlowCtrl=none ; Transmit delay per character (in msec) DelayPerChar=0 ; Transmit delay per line (in msec) DelayPerLine=0 このパラメータBaudRateを、9600から115200に変更すればOKです。上書き変更しても良いですし、今の設定をコメントアウトしてから追記しても良いです。 コメントアウトは行の先頭に;を入れればOKです。下記の例では従来の9600設定をコメントアウトし、その下の行に新規に115200に設定する行を追加しました。\n1 2 3 ; Baud rate ;BaudRate=9600 BaudRate=115200 この状態でTera Termを起動すれば、ボーレート（速度）のデフォルト設定が115200になっているはずです。\nデフォルト接続をTCP/IPからシリアルに変更する 上記のボーレートのデフォルト値の変更だけでもそれなりに便利にはなるのですが、さらに便利にしたい人向けに補足します。 「Tera Termは主にシリアル接続に使っていてSSHとかには使わないよ」という人向けです。\nTera Termを起動すると、下記の赤枠のようにTCP/IPの方にチェックが入っていると思います。 これをいちいち「シリアル」にチェックしてからさらにCOMポート番号を選ぶというのは面倒です。 そこで、デフォルトでシリアル接続かつ特定のCOMポート番号に接続するようにします。 すでに述べたように、Tera Termのデフォルト設定は TERATERM.INIファイルに記載されています。このファイルを修正します。\nTERATERM.INIの設定箇所 ポート番号の設定はTERATERM.INIの310行目あたりにあります。デフォルトは1なので、今回は6になるように設定してみます。\n1 2 3 4 ; Serial port parameters ; Port number ;ComPort=1 ComPort=6 次に、接続先をTCP/IPからシリアルに変更します。これは、TERATERM.INIの130行目あたりにあります。 Portというパラメータがそれです。デフォルトではtcpip となっていますので、これを serialに修正します。 下記に修正例を示します。\n1 2 3 ; Port type (serial/tcpip) ;Port=tcpip Port=serial これで、デフォルトでCOMポート6（ボーレート115200）に接続しに行くようになります。\nまとめ 今回は、Tera Term起動時に毎回設定をする手間を省くためにTERATERM.INIの設定方法をご紹介しました。今回紹介したこと以外にもいろいろと設定ができます。例えばウィンドウを透過にしたり、なんかもできます。皆さんの相棒として手に馴染むようにどんどんカスタマイズしてみていただければと思います！\n本のご紹介 Tera Term のメンテナの平田豊さんが本を出版されました。 不肖私めも帯にコメントを書かせていただきました。\nリンク ","permalink":"https://nagayasu-shinya.github.io/posts/teraterm-baud-rate-default/","summary":"\u003cp\u003e組み込みソフト開発でよく使われているTera Termのデフォルト設定値の変更方法を説明します。\u003c/p\u003e","title":"Tera Term のデフォルト値を変更して便利に使う"},{"content":"WSLにて、PACファイルを使っている環境下での設定方法も書きます。\nWindows上でLinuxライクな環境を使うにはWSLやGit for Windowsなどがありますね。 その際、職場で使うときは、Proxyの設定が必要になることが多いと思います。\n今回はその設定方法を解説します。また、普通のProxyサーバでなくPACファイルを使っている環境下での設定方法も書いておきます。PACファイルとは、接続するProxyサーバを自動で振り分けるスクリプトです。\n通常のProxyサーバの場合 基本的にWindows側にて設定されているサーバを使えばOKです。 WSLの場合と同じですね。こちらにも手順を載せておきます。\nまずは現状のプロキシ設定を確認します。 はじめに「コントロールパネル」を開きます。そのなかの「インターネットオプション」を選択します。\n次に、「接続」タブを選択し「LANの設定」をクリックします。 そうするとProxyなどの設定をするウィンドウが開きます。 そこにProxyのアドレスとポート番号が書いてありますのでそれをメモします。\n次に、WSLにてそのProxy設定をします。 具体的にはhttp_proxyとhttps_proxyという環境変数を設定する必要があります。\nホームディレクトリ直下の.bashrcに下記のように設定を書いておけば良いと思います。 これでログイン時に自動で設定されます。\nproxy-host proxy-portには、先ほど確認したプロキシのアドレスとポート番号を入れてください。 usernameとpasswordはProxyのユーザ名とパスワードです。\n1 export http_proxy=http://username:password@proxy-host:proxy-port export https_proxy=http://username:password@proxy-host:proxy-port PACファイルを使っているProxyサーバの場合 通常は上記のように単純にProxyサーバのURLをコピペすればいいのですが、PACを使用している環境ではそのままコピペしても動作しません。 一手間が必要です。その方法を示します。\nPACファイルのURLを確認 まず、ProxyサーバのURLを確認します。 PACを使用している場合は、下記の青枠で囲んだように「自動構成スクリプトを使用する」にチェックが入っています。 そしてそのすぐ下の「アドレス」のところにURLが書かれています。 これをメモします。大抵の場合、拡張子が.pacになっていると思います。\nPACファイルからProxyサーバのURLを調べる 次に、PACファイルの中身を調べます。 先ほどメモしたURLを、WEBブラウザなどで開きます。 中身はただのスクリプトファイルなのでなんでも開けます、ChromeでもEdgeでもなんでもいいです。 下記はPACファイルをダウンロードしている様子です。 ダウンロードした後、メモ帳なりWordなり、お好きなエディタで開いてください（もちろん、ダウンロードせずに直接ブラウザ上で表示しても構いません）。\nPACファイルの中身は、下記のような function FindProxyForURL (url, host)が記載されているはずです。 実際はもっと長いかもしれませんが、構造的には同じようになっているはずです。\n下記のように returnのところにさまざまなProxyサーバのURLが記述されています。 この中から該当するものをメモします。 大抵の場合、最後の方のelseのところに書いてあるProxyサーバが該当します。 下記の例ですと「PROXYproxy.YYYY.co.jp:8080」ですね。これをメモします。\n1 2 3 4 5 6 7 8 9 10 11 function FindProxyForURL (url, host) { if (shExpMatch(host, \u0026#34;www.FOO.co.jp\u0026#34;) return \u0026#34;PROXY proxy.FOO.jp:8080\u0026#34;; else if (shExpMatch(host, \u0026#34;www.BAR.co.jp\u0026#34;) return \u0026#34;PROXY proxy.BAR.jp:8080\u0026#34;; else if (host.match(/.local$/)) return \u0026#34;DIRECT\u0026#34;; else return \u0026#34;PROXY proxy.YYYY.co.jp:8080\u0026#34;; } PACファイルから調べたProxyサーバを設定する あとは、先ほど調べたProxyサーバを設定すればOKです。 通常のProxyサーバの設定と同様です。 具体的にはhttp_proxyとhttps_proxyという環境変数を設定します。\nホームディレクトリ直下の.bashrcに下記のように設定を書いておけば良いでしょう。 これでログイン時に自動で設定されます。\nproxy-host proxy-portには、先ほど確認したプロキシのアドレスとポート番号を入れてください。\nusernameとpasswordは、Proxyのユーザ名とパスワードです。\n1 export http_proxy=http://username:password@proxy-host:proxy-port export https_proxy=http://username:password@proxy-host:proxy-port PACファイルから調べたProxyサーバのURLがproxy.YYYY.co.jp:8080でしたら、例えばこんな感じでしょうか。\n1 export http_proxy=http://username:password@proxy.YYYY.co.jp:8080 export https_proxy=http://username:password@proxy.YYYY.co.jp:8080 これで、ログイン時にProxyサーバが設定されるはずです。\nまとめ 今回はWSLでのProxyサーバの設定方法を解説しました。 また、PACファイル（プロキシ自動設定ファイル）を使っている場合の設定方法も解説しました。 これでパッケージのインストールやアップデートができるようになるはずです！\n","permalink":"https://nagayasu-shinya.github.io/posts/wsl-proxy-configuration/","summary":"\u003cp\u003eWSLにて、\u003ca href=\"https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7%E8%87%AA%E5%8B%95%E8%A8%AD%E5%AE%9A\"\u003ePACファイル\u003c/a\u003eを使っている環境下での設定方法も書きます。\u003c/p\u003e","title":"WSLでのProxy設定方法｜PACファイルでも"},{"content":"C言語でのデバッグプリントの効率的なやり方を説明します。\nデバッグするときはデバッガを使うのが定石ですが、なんらかの事由によりそれがかなわないときもあるでしょう。 そのとき頼りになるのが片っ端からprintf 文をいれていく方法、いわゆるプリントデバッグです。 CPUのレジスタなどはわかりませんが、単にどこまでプログラムが実行されたか知りたいだけ、とかならこれでもなんとかなります。2分探索で切り分けていけば、仮に100万行のコードでも高々20回の試行ですみます。 今回はこのデバッグプリントのTipsをご紹介します。\nデバッグビルドとリリースビルドとで有効無効を切り替える printfデバッグするときには、リリース時にはそのデバッグプリント文は削除する必要があります。 手作業でそれをやっていては削除漏れが起きてしまう可能性大です。そこで、プリプロセッサの条件コンパイルをつかってそれを自動化しましょう。\n例としては下記のようになります。この例では、マクロDEBUG_BUILDが定義されていればデバッグプリントが有効に、定義されていなければ無効になります。 コードの内容の説明はあとでします。ひとまずここでは、有効無効の切り替え方をみていきます。\n1 2 3 4 5 6 7 #ifdef DEBUG_BUILD # define DEBUG_PUTS(str) puts(str) # define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__); #else # define DEBUG_PUTS(str) # define DEBUG_PRINTF(fmt, ...) #endif ヘッダファイル内のマクロ定義でデバッグプリント有効無効を切り替える このデバッグプリントの有効無効の切り替え方ですが、一番シンプルなのはマクロDEBUG_BUILDをヘッダファイル内で定義してしまうことです。 例えば下記のようなヘッダファイルを作って、それをインクルードするようにすればOKです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 #ifndef MY_DEBUG_H_INCLUDED #define MY_DEBUG_H_INCLUDED #define DEBUG_BUILD // enable debug print. #ifdef DEBUG_BUILD # define DEBUG_PUTS(str) puts(str) # define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__); #else # define DEBUG_PUTS(str) # define DEBUG_PRINTF(fmt, ...) #endif #endif 無効にしたい場合は下の行をコメントアウトすればOKです。\n1 #define DEBUG_BUILD // enable debug print. このやり方はシンプルなのでわかりやすいのですが、いちいちヘッダファイルを書き換えて#define DEBUG_BUILDを有効にしたりコメントアウトしたり、という手間があります。\nコンパイルオプションでデバッグプリント有効無効を切り替える 一方、ヘッダファイルを書き換えなくてもよい方法があります。 ヘッダファイルには、下記のようにDEBUG_BUILDの定義は書きません。 その代わり、コンパイルオプションを利用します。\n1 2 3 4 5 6 7 8 9 10 11 12 #ifndef MY_DEBUG_H_INCLUDED #define MY_DEBUG_H_INCLUDED #ifdef DEBUG_BUILD # define DEBUG_PUTS(str) puts(str) # define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__); #else # define DEBUG_PUTS(str) # define DEBUG_PRINTF(fmt, ...) #endif #endif GCCやたいていのコンパイラには-Dオプションがあります。 これはコンパイル時にマクロを定義するためのオプションです。たとえば、\n1 gcc hoge.c -DFUGA -c -o hoge.o とすれば、これはhoge.cの先頭に #define FUGAと書いたときと同じようにコンパイルされます。 これを利用して、\n1 gcc hoge.c -DDEBUG_BUILD -c -o hoge.o とすれば、そのファイルは先頭に #define DEBUG_BUILDと書いたときとおなじになり、DEBUG_BUILDが有効になります。 Makefileを利用しているなら、CFLAGS変数にこのオプションを追加すればOKでしょう。 ただし、たいていのMakefileの書き方では、コンパイルオプションが変わっても自動ではリビルドしてくれないので、 明示的にmake cleanをするのを忘れずに。\nNote\nGNU Makefile のフレームワークを GitHub のgnu-make-framework-zenに置いています。 ご参考までに。\n可変長引数とマクロ関数 簡単にコードの説明をします。 まず、フォーマット引数の必要がない場合、つまり%dや%sなどがない場合はputsで事足りるのでそれを使います。 putsは引数は１つですので普通のマクロ関数で定義すればOKです。\nフォーマット引数が必要な場合はprintfを使います。printfは可変長引数をとるので、関数マクロも可変長引数をとれるようにします。 関数マクロDEBUG_PRINTFの引数の ...はC99からの新機能で、可変長引数を表します。その可変長引数に対応するのが__VA_ARGS__です。 たとえば\n1 DEBUG_PRINTF(\u0026#34;%s, %d.\\n\u0026#34;, \u0026#34;hoge\u0026#34;, 3); としたとき、可変長引数には\u0026quot;hoge\u0026quot;, 3が対応し、\n1 printf(\u0026#34;%s, %d.\\n\u0026#34;, \u0026#34;hoge\u0026#34;, 3); と展開されます。ちなみにfmtには最初の引数\u0026quot;%s, %d.\\n\u0026quot;が対応します。 注意点として、この例ではDEBUG_PRINTFとDEBUG_PUTSを使い分けなくてはいけません。 フォーマット引数のない場合はDEBUG_PRINTFはつかえません。 可変長引数の...および__VA_ARGS__に対応するものがないためです。たとえば\n1 DEBUG_PRINTF(\u0026#34;hello.\\n\u0026#34;); とした場合、\n1 printf(\u0026#34;hello.\\n\u0026#34;,); と展開されてしまい、よけいなカンマが残ってしまいます。\ngcc拡張を使ってもっと便利に 上記の例では、printfへのフォーマット引数の有無でDEBUG_PUTSとDEBUG_PRINTFを使い分ける必要がありました。 それはめんどくさいのですが、gcc拡張がつかえるコンパイラなら、下記のように書くことができます。文字連結のマクロ ##を追加します。\n1 2 3 4 5 #ifdef DEBUG_BUILD # define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__); #else # define DEBUG_PRINTF(fmt, ...) #endif これによりDEBUG_PRINTF(\u0026quot;hello.\\n\u0026quot;);のようにフォーマット引数がない場合でもDEBUG_PRINTFを使えるようになります。 今回利用しているgcc拡張についての詳細は、 3.6 Variadic Macrosのサイトを見てみてください。\n自動でファイル名、関数名、行数も表示する どこまでプログラムが進んだかを知りたいときには、ファイル名や行数を表示させると便利です。 事前定義済みマクロ（プリでファインドマクロ）を使えばそれが簡単に可能です。 ファイル名は__FILE__ 行数は__LINE__で取得できます。関数名はC99からの新機能で__func__で取得可能です。 関数名のマクロは小文字なので注意してください。\nこれらを使った例を下に示します。このようなヘッダファイル my_debug.h を作ったとします。\n1 2 3 4 5 6 7 8 9 #define DEBUG_BUILD #ifdef DEBUG_BUILD # define DEBUG_PRINTF(fmt, ...) \\ printf(\u0026#34;file : %s, line : %d, func : %s, \u0026#34; fmt, \\ __FILE__, __LINE__, __func__, ## __VA_ARGS__); #else # define DEBUG_PRINTF(fmt, ...) #endif それを下記のようにコールしたとします。\n1 2 3 4 5 6 7 8 9 10 11 12 #include \u0026#34;my_debug.h\u0026#34; int main(void) { DEBUG_PRINTF(\u0026#34;hoge.\\n\u0026#34;); DEBUG_PRINTF(\u0026#34;fuga.\\n\u0026#34;); DEBUG_PRINTF(\u0026#34;pino.\\n\u0026#34;); return 0; } 実行結果は下記のようになります。このように自動的にファイル名や関数名、行数が表示されます。\n1 2 3 file : main.c, line : 5, func : main, hoge. file : main.c, line : 7, func : main, fuga. file : main.c, line : 9, func : main, pino. もしくは do-while をつかってprintf２つで書くことも可能です。 実行結果は同じなります。お好みでお好きな方をどうぞ。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #ifndef MY_DEBUG_H_INCLUDED #define MY_DEBUG_H_INCLUDED #define DEBUG_BUILD #ifdef DEBUG_BUILD # define DEBUG_PRINTF(fmt, ...) \\ do { \\ printf(\u0026#34;file : %s, line : %d, func : %s, \u0026#34;, \\ __FILE__, __LINE__, __func__); \\ printf(fmt, ##__VA_ARGS__); \\ } while (0) #else # define DEBUG_PRINTF(fmt, ...) #endif #endif 補足 ここまでくれば、割と便利にプリントデバッグできるかなと思います。念のため、さらに補足をしておきます。\nマクロ関数をdo { } while(0) で囲む理由 下記のコードを見て「なぜマクロ関数をdo while(0)で囲んでいるんだろう、無駄なのでは」と思った方もいるかもしれません。 これはマクロ関数を使うときにイディオムです。わりとよく使われます。\n1 2 3 4 5 6 # define DEBUG_PRINTF(fmt, ...) \\ do { \\ printf(\u0026#34;file : %s, line : %d, func : %s, \u0026#34;, \\ __FILE__, __LINE__, __func__); \\ printf(fmt, ##__VA_ARGS__); \\ } while (0) わかりやすいように、次の2つのマクロ関数を考えてみます。処理内容はテキトウです。 do while があるかどうかに着目してください。\n1 2 #define MACRO_FUNC1(...) { printf(\u0026#34;MACRO_FUNC1 \u0026#34;); printf(__VA_ARGS__);} #define MACRO_FUNC2(...) do { printf(\u0026#34;MACRO_FUNC2 \u0026#34;); printf(__VA_ARGS__);} while(0) この2つの関数を下記のようにコールしたとします。\n1 2 3 4 5 6 7 8 9 void func(int tmp) { if (tmp) MACRO_FUNC1(\u0026#34;hoge\\n\u0026#34;); else MACRO_FUNC2(\u0026#34;fuga\\n\u0026#34;); return; } すると下記のように展開されます。まずい点がありますね。\n1 2 3 4 5 6 7 8 9 void func(int tmp) { if (tmp) { printf(\u0026#34;MACRO_FUNC1 \u0026#34;); printf(hoge);}; else do { printf(\u0026#34;MACRO_FUNC2 \u0026#34;); printf(fugue);} while(0); return; } ダメな点がわかりやすいように改行とインデントを入れてみます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 void func(int tmp) { if (tmp) { printf(\u0026#34;MACRO_FUNC1 \u0026#34;); printf(hoge); } ; else do { printf(\u0026#34;MACRO_FUNC2 \u0026#34;); printf(fugue); } while(0); return; } そうですね、if節の終わりの}の後に余計なセミコロンがあります。 これは邪魔です、コンパイルエラーになります。do-while(0)の方は、セミコロンまでが一つの文なので問題ありません。 仮にif節の方にdo-while(0)のマクロ関数を持ってきてもコンパイルエラーにはなりません。 このようにぶら下がりif文で予期しないエラーを出さないためのイディオムがdo-while(0)なわけですね。\nprintfのバッファリング 実は下記の書き方、途中でセグメンテーションフォルトなどで異常終了する場合、期待通りに動かないかもしれません。 というのは、printfは一時的に出力をバッファリングして（溜めて）から、一気に出力するからです。\n1 2 3 4 5 6 # define DEBUG_PRINTF(fmt, ...) \\ do { \\ printf(\u0026#34;file : %s, line : %d, func : %s, \u0026#34;, \\ __FILE__, __LINE__, __func__); \\ printf(fmt, ##__VA_ARGS__); \\ } while (0) 標準関数のsetvbufでバッファリングの挙動を変えることは可能ですが、素直にfprintfで標準エラー出力に吐き出した方が賢いかもしれません。fprintfを使った場合は下記のようになりますね。\n1 2 3 4 5 6 # define DEBUG_PRINTF(fmt, ...) \\ do { \\ fprintf(stderr, \u0026#34;file : %s, line : %d, func : %s, \u0026#34;, \\ __FILE__, __LINE__, __func__); \\ fprintf(stderr, fmt, ##__VA_ARGS__); \\ } while (0) まとめ 今回は、現場で案外使われる手法デバッグプリントについて説明しました。 ついでに条件コンパイルやdo-while(0)イディオムなども説明しました。ラクしてデバッグできるようになるといいなと思います！\n","permalink":"https://nagayasu-shinya.github.io/posts/debug-printf-techniques/","summary":"\u003cp\u003eC言語でのデバッグプリントの効率的なやり方を説明します。\u003c/p\u003e","title":"printf デバッグ（デバッグプリント）の書き方"},{"content":"C/C++言語の静的解析ツール Splintの紹介です。\nC/C++言語の静的解析ツール、使っていますか？仕事で使う場合は有償のもの（QACやpgreliefなど）を使うことがおおいと思います。しかし休みの日に家でコードを書いたりするときにも個人で静的解析ツールを使いたい場合もあると思います。そこで今回は、フリーの静的解析ツール Splintについて説明します。 静的解析ツールを使うことによってコードのバグを減らして品質を上げることができます。また、休みの日に孤独にコードを書いているときでも、 レビューの代わりとして使って自身のコーディング能力をアップさせることもできます。\nSplint のインストール Splintでは「インストール用のバイナリはあまり更新されないから、ソースコードからビルドすることをオススメするよ！」というようなことが書いてあります。 が、自分でビルドするのは手間なので、今回はインストール用のバイナリを素直に使う方法を説明します。\nMac OS X の場合 Homebrew を使えば簡単です。\n1 brew install splint Linux の場合 Linuxでもパッケージマネージャが対応していれば簡単です。Ubuntuの場合は下記でOKです。\n1 sudo apt-get install splint Windows にインストールする場合 Windows向けのインストーラも提供されています。インストール自体は簡単です。他のOSと違って、インストール後に3つの環境変数の設定が必要なのでそれを忘れないでください。\nまず、splint_win32に .msi と .zipが置いてありますので、どちらかをダウンロードして、インストールします。 .msiでGUIなインストーラを使用してもいいですし、.zipを解凍して任意のとこに置いてもいいですね。\n次に下記の3つの環境変数を設定します。設定の方法は特に特別な手順は必要ありません。\nLARCH_PATH LCLIMPORTDIR include 普通に、マイコンピューターのアイコンを右クリックして「詳細設定」タブをクリックして「環境変数」から設定すればいいです。 もちろん、コマンドプロンプトから設定してもいいです。\n環境変数 LARCH_PATH の設定 LARCH_PATHには、Splintをインストールしたフォルダの直下にあるlibというフォルダのパスを設定してください。 コマンドプロンプトで行うなら下記のようにすればOKです。 ここではSplintをC:\\Programs\\ の下にインストールしたという前提です。\n1 set LARCH_PATH=C:\\Programs\\splint\\lib\\ 環境変数 LCLIMPORTDIR の設定 LCLIMPORTDIRには、Splintをインストールしたフォルダの直下にあるimportsというフォルダのパスを設定してください。 コマンドプロンプトで行うなら下記のようにすればOKです。\n1 set LCLIMPORTDIR=C:\\Programs\\splint\\imports\\ 環境変数 include の設定 最後にincludeの設定です。これにはstdlib.hなどの標準ヘッダファイルのあるフォルダのパスを指定してください。\nこの変数が設定されていないと、下記のように標準ライブラリのヘッダファイルが見つからないというエラーが出ますので注意してください。\n1 2 3 4 5 6 7 8 9 10 11 12 /c/Programs/splint/bin/splint.exe +skip-sys-headers +posixlib -I../src/modules/embunit -I../src/targets/sample_embunit ../src/targets/sample_embunit/person.c || : Splint 3.1.2 --- 25 Aug 2010 ../src/targets/sample_embunit/person.c(1,19): Cannot find include file stdio.h on search path: ../src/modules/embunit;../src/targets/sample_embunit;C:/include;C:/local/include Preprocessing error. (Use -preproc to inhibit warning) ../src/targets/sample_embunit/person.c(2,20): Cannot find include file stdlib.h on search path: ../src/modules/embunit;../src/targets/sample_embunit;C:/include;C:/local/include ../src/targets/sample_embunit/person.c(3,20): Cannot find include file string.h on search path: ../src/modules/embunit;../src/targets/sample_embunit;C:/include;C:/local/include Preprocessing error for file: ../src/targets/sample_embunit/person.c *** Cannot continue. 使い方 使い方は簡単です。下記のような感じで .c ファイルを渡すだけです。\n1 splint -I./ -I../my_include +weak +posix-lib hoge.c ちなみに実際の実行結果は下記のようになります。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ /c/Programs/splint/bin/splint.exe +skip-sys-headers +posixlib -I../src/modules/embunit -I../src/targets/sample_embunit ../src/targets/sample_embunit/AllTests.c Splint 3.1.2 --- 25 Aug 2010 ../src/targets/sample_embunit/AllTests.c: (in function main) ../src/targets/sample_embunit/AllTests.c(9,22): New fresh storage (type TestRef) passed as implicitly temp (not released): CounterTest_tests() A memory leak has been detected. Storage allocated locally is not released before the last reference to it is lost. (Use -mustfreefresh to inhibit warning) ../src/targets/sample_embunit/AllTests.c(10,22): New fresh storage (type TestRef) passed as implicitly temp (not released): PersonTest_tests() ../src/targets/sample_embunit/AllTests.c(6,15): Parameter argc not used A function parameter is not used in the body of the function. If the argument is needed for type compatibility or future plans, use /*@unused@*/ in the argument declaration. (Use -paramuse to inhibit warning) ../src/targets/sample_embunit/AllTests.c(6,27): Parameter argv not used Finished checking --- 4 code warnings 引数のオプションについて、ひとまず使うために必要なことを下記に説明します。\nヘッダファイルの探索パスの設定 splintがヘッダファイルを探し出せるように、パスを教えてあげる必要があります。 stdlib.hなどの標準ライブラリは、前述した環境変数include で指定されたところを探しに行きます。 自分で作ったヘッダファイルは、別途教えてあげる必要があります。gccなどの通常のコンパイラと同じく-Iを使います。\n例えばカレントディレクトリと../my_includeというディレクトリにヘッダファイルがある場合は、-I./ -I../my_includeとすればOKです。通常のコンパイラと一緒ですね。 ですのでコンパイルしているときのオプションをそのまま渡せば基本的にOKです。\nただし1点だけ注意が必要です。コンパイラの場合は-Iとパスの間にスペースがあっても構いません。例えば-I ./ -I ../my_includeでもOKです。 ですが splint はダメです。必ず -I の直後にはスペースをつけずに、すぐにパスを書くようにしてください。\n標準ライブラリなどの設定 どのライブラリを使うかの設定が必要です。デフォルトではC言語のライブラリ（ANSI)が設定されています。 もし、C言語の標準でないPOSIX関数を使っている場合は posix-libを指定してください。よくわからなければPOSIXにしておけば大丈夫でしょう。\nここで注意点があります。ライブラリを指定するときはハイフン- でなくプラス+を使用してください。 つまりsplint -posix-libでなくsplint +posix-libとしてください。 基本的にSplintではハイフン-は無効化、プラス+は有効化を示します。\nフラグの設定 どのような指摘を有効にするか、または無効にするかを細かく指定できます。ただし、通常のLinuxコマンドとは作法が異なるので注意してください。 普通のコマンドは、-hogeのようにハイフン-でオプションを指定しますが、Splintはプラス+とハイフン-を使い分けなければいけません。\nプラス+は有効か、ハイフン-は無効化の意味となります。例えばhogeという指摘を有効にしたい場合は-hogeでなく+hogeとします。 -hogeは無効にするという意味になってしまいます。\n例として、バッファーオーバーフローにつながる可能性のある関数を使用している場合に指摘するbufferoverflowhigh を有効にする場合、 splint +bufferoverflowhighのように指定します。すると下記のような指摘が出力されます。 ちなみにこれは sprintf を使っているから怒られていますね。snprintfを使うべきでしょう。\n1 2 3 ../src/targets/sample_embunit/person.c:89:4: Buffer overflow possible with sprintf. Recommend using snprintf instead: sprintf Use of function that may lead to buffer overflow. (Use -bufferoverflowhigh to inhibit warning) どのようなフラグがあるかは、Appendix Bを参照してください。\nMakefile の書き方の例 Splintの利用例として、Makefile をどのように書けばいいかを説明します。\nインクルードパスの設定 前述した通り、Splintを使うときにはヘッダファイルのあるパスを指定しなければいけません。 すでにMakefileでビルド環境が構築している場合は簡単に設定できます。 例えば下記のような、.cファイルから.oファイルをコンパイルするためのパタンルールがあったとします。 CFLAGS変数にヘッダのパス設定-Iも含まれているとします。\n1 2 3 %.o : %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o このCFLAGSから-Iオプションだけ取り出すには $(filter -I%,\\$(CFLAGS))とすればOKです。下記のようにすればOKです。\n1 2 3 4 5 SPLINT_FLAGS = $(filter -I%,$(CFLAGS)) %.o : %.c $(SPLINT) $(filter -I%,$(CFLAGS)) $\u0026lt; $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o ここで注意点が1つあります。 コンパイラは-I ../my_includeのように -Iとパスの間にスペースがあってもOKですが、SplintではNGです。 -Iのあとにスペースを入れないでください。-I../my_includeのようにしてください。\n最後に、システムのヘッダファイルを解析しないようにします。 通常システムに問題はないはずですし、指摘があってもおいそれと変更できませんしね。 オプションは +skip-sys-headers をつければOKです。\n1 2 3 4 5 6 SPLINT_FLAGS = $(filter -I%,$(CFLAGS)) SPLINT_FLAGS += +skip-sys-headers %.o : %.c $(SPLINT) $(SPLINT_FLAGS) $\u0026lt; $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o ライブラリの設定 プログラムがつかうライブラリを指定してあげる必要があります。 ANSIかPOSIXかUnixのどれかを選択します。ANSIなら +ansi-lib POSIXなら +posix-lib Unixなら +unix-lib のオプションをわたします。 μITRONのようなLinuxコマンドを使わない環境ならANSI、LinuxなどはPOSIXとすればよいかと思います。ここではPOSIXにしてみました。\n1 2 3 4 5 6 7 SPLINT_FLAGS = $(filter -I%,$(CFLAGS)) SPLINT_FLAGS += +skip-sys-headers SPLINT_FLAGS += +posix-lib %.o : %.c $(SPLINT) $(SPLINT_FLAGS) $\u0026lt; $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o 終了ステータスの処理 Splintは一つでも指摘があるとエラーステータスを返します。 そのため、そこで make が中断されてしまいます。 make にて途中でエラーが出ても全コマンドを実行する方法にその対処法を書いていますのでご参照ください。\n最終的には下記のようにすればOKです。\n1 2 3 4 5 6 7 8 9 SPLINT_FLAGS = $(filter -I%,$(CFLAGS)) SPLINT_FLAGS += +skip-sys-headers SPLINT_FLAGS += +posix-lib IGNORE_EXIT_STATUS = || : %.o : %.c $(SPLINT) $(SPLINT_FLAGS) $\u0026lt; $(IGNORE_EXIT_STATUS) $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o gnu-make-framework-zen にMakefile 全体を置いていますので、興味があればみてみてくださいませ。\nまとめ フリーの静的解析ツール Splintのインストールと設定の仕方から Makefile の設定方法までを説明しました。 かなり細かいことまで指摘してくれるツールであり、またフリーですので、いちど試してみてはいかがでしょうか？ おもいもよらぬ指摘がでたりするかもしれませんよ！\n","permalink":"https://nagayasu-shinya.github.io/posts/static-analysis-splint-c/","summary":"\u003cp\u003eC/C++言語の静的解析ツール Splintの紹介です。\u003c/p\u003e","title":"C言語の静的解析ツールを使ってみよう！｜Splint"},{"content":"GNU make にて、途中でエラーが起きてもそのまま処理を継続させる方法を説明します。\nmake は途中でエラーが出るとそこで処理を中断します。例えばC言語でプログラムをビルドするとき、途中でコンパイルエラーが出ているのにそのまま続けても意味がないですし、続けてもリンクエラーになりますから。妥当な挙動と言えます。 しかし、makeにて途中でエラーが出ても最後まで続けて欲しい場合もあります。例えば、プロジェクトの立ち上げ時でまだビルドが通らない状況だけどひとまず現時点でコンパイルエラーが何個起きるか数えたいときや、静的解析ツールを実行していて途中で指摘があっても全ファイルチェックしたいとき、などです。 その場合の対処法を2パタン説明します。\nmake のオプション -k (--keep-going) 基本的にはこれを使えばOKです。オプション名通り、エラーが起きても処理を続けてくれます。具体的には、ターゲットの生成に失敗しても次のターゲットを生成しに行く、という挙動になります。 例えばC言語でプログラムをビルドするときは下記のようなパタンルールが記述されていると思います。\n1 2 %.o : %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o これは、拡張子 .o で終わるターゲットを作成するために $(CC) 使って .cファイルをコンパイルせよ、という意味です。 hoge.c fuga.c piyo.cという3つのファイルがあったとすると、ターゲットはhoge.o fuga.o piyo.oとなります。\nこれを順番に生成していくわけですが、もしfuga.oのコンパイルに失敗した場合、デフォルトではそこで make は中断されます。 ですが -k(--keep-going) をつけておくと、fuga.cのコンパイルに失敗してもhoge.cもpiyo.cもコンパイルが実行されていきます。\n終了ステータスを「:」で0（正常終了）にする たいていは上記の --keep-going で事足りるのですが、それではダメなケースもあります。 例えばコンパイルと同時に静的解析ツールを実行する場合を考えます。パタンルールを下記のように書いたとします。$(LINT)で静的解析を実行するという記述ですね。\n1 2 3 %.o : %.c $(LINT) $(LINTFLAGS) $\u0026lt; $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o もしここで、静的解析ツールが問題のある記述を発見しエラーを返してきたとします。 --keep-going をつけていれば問題なくコンパイルも実行されそうですが、実はそうではありません。 --keep-going はターゲットの生成に失敗しても次のターゲットを生成しにいく、というオプションです。 ターゲットの生成に必要な処理を全部実行するというわけではありません。\nこの場合ですと、最初の$(LINT)の静的解析ツールでエラーだった場合、次の行の$(CC)のコンパイルは実行されずにこのターゲットの生成は終了してしまいます。 わかりづらいと思うので例を挙げます。hoge.c fuga.c piyo.cという3つのファイルがあり、fuga.cに静的解析ツールがエラーを出すコードが含まれていた場合を考えます。\nhoge.cは静的解析もコンパイルも通ります。そして問題のfuga.cに処理が移ったとき、静的解析ツール$(LINT)にてエラーが出ます。 ここでfuga.cの処理は諦めてその次のpiyo.cへ処理が移ります。つまりfuga.cのコンパイルは実行されません。\nこのような問題に対処するにはどうすればいいか。静的解析ツールの終了ステータスを必ず正常終了になるように工夫してあげればOKです。 もう少し正確にいうと、静的解析ツールが失敗したときには、必ず成功するコマンドを実行するようにします。具体的には下記のようにします。 $(LINT)の行の最後の|| :が付いていますね。\n1 2 3 %.o : %.c $(LINT) $(LINTFLAGS) $\u0026lt; || : $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o ||は論理和ですので、左の処理が失敗したときだけ右の処理を実行します。:は「何もしない」という処理ですので、必ず成功します。 ですので、結果的に静的解析が必ず正常終了したように見えます。こうすることで、仮に静的解析ツールがエラーを返しても、期待通りコンパイルまで実行されるようになります。\nMakefile の例 この方法を使っている makefile の例を下記に挙げます。 https://github.com/nagayasu-shinya/gnu-make-framework-zen 該当箇所だけ抜粋してみます。こんな感じです。ご参考まで。\n1 2 3 4 5 IGNORE_EXIT_STATUS = || : %.o : %.c $(SPLINT) $(SPLINT_FLAGS) $(filter -I%,$(CFLAGS)) $\u0026lt; $(IGNORE_EXIT_STATUS) $(CCACHE) $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o 参考書籍はこれです。\nリンク まとめ 今回は、makeで途中でエラーが発生してもすべての処理を実行する方法を述べました。基本的には makeのオプション -k (--keep-going)でOKです。 ただしターゲットを生成するのに複数のコマンドを実行する必要がああるときは、:コマンドをうまく使ってエラーが発生しないようにしなければいけません。意外と見落としがちなことですので注意してください！！\n","permalink":"https://nagayasu-shinya.github.io/posts/make-continue-on-error/","summary":"\u003cp\u003eGNU make にて、途中でエラーが起きてもそのまま処理を継続させる方法を説明します。\u003c/p\u003e","title":"make にて途中でエラーが出ても全コマンドを実行する方法"},{"content":"実行可能ファイルのシンボル情報を削除して情報漏えいのリスクを下げる方法を説明します。\n業務などでC/C++言語で作ったプログラム（実行可能ファイル）をリリースしたり他の人に渡すことがあると思います。 そのときにシンボル情報というものに気をつけていますでしょうか? シンボル情報というのは関数名とか変数名などの情報です。\n例えばデバッガなんかで変数の値をのぞいたり、特定の関数まで実行したりできますよね。 それは実行可能ファイルにシンボル情報があるからできるわけです。どこにどんな変数や関数があるかラベルづけされているわけですね。 このように実行可能ファイルにはシンボル情報が含まれているんですが、場合によってはこれが情報漏洩の原因になりかねません。\nデバッグ用の関数や変数や隠し機能などが漏れてしまう可能性があります。また、ビルドしたときのパス情報なども含まれるためにユーザ名なんかもわかってしまうかもです。 そこで今回は、実行可能ファイルからシンボル情報をみる方法を示したうえで、それを削除する方法を示します。\nCaution\nライブラリ(.a, .so)やオブジェクトファイル(.o)からシンボル情報を削除すると、 リンクできなくなってしまうので要注意です！ リンカはシンボル情報を参照してそれらを結合するので消してはダメです！\nシンボル情報をのぞいてみよう シンボル情報を見るには nm コマンドを使用します。今回の例はWindows MINGW上で実行していますが、Linuxでも同様です。\nためしに自前でビルドした実行可能ファイルに対してnmを実行したところ、下記のようになりました。 左の数字はアドレス、真ん中はデータの種類、右はシンボル名です。なんとなくたくさんのデータや関数があるんだなぁ、というのがわかるかなと思います。 このように、nmでシンボル情報を表示することで、関数名やファイル名が簡単に見ることができてしまいます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 $ nm ./ccache.exe 0000000000436000 d .CRT$XCA 0000000000436008 d .CRT$XCAA 0000000000436010 d .CRT$XCZ 0000000000411560 T dirname 00000000004029c0 t do_copy_or_move_file_to_cache 000000000040c030 t do_debug_text.isra.0.part.1 000000000040c090 t do_hash_buffer 000000000040c060 t do_hash_buffer.part.2 00000000004128d0 t do_x_unlink 000000000042e2a8 b done.97297 0000000000433790 b dtoa_CS_init 00000000004337a0 b dtoa_CritSec 000000000041dbb0 t dtoa_lock 000000000041dc80 t dtoa_lock_cleanup 0000000000403100 t dump_log_buffer_exitfn 000000000041f1b8 T dup 0000000000432c20 b emu_pdata 0000000000432b20 b emu_xdata 000000000042e018 b envp 000000000041f0a0 T exit 000000000042e230 b exit_functions 000000000040bf80 T exitfn_add 000000000040bfc0 T exitfn_add_last 000000000040bf30 T exitfn_add_nullary 000000000040bea0 T exitfn_call 000000000040bef0 T exitfn_init 000000000040ce60 T extension_for_language 0000000000425ba0 r extensions 0000000000402790 t failed 0000000000411060 T fatal 000000000041f098 T fclose さらに実行可能ファイルの中身をのぞいてみよう nmでもいろいろな情報が見ることができますが、さらにもっと情報が見れないか試してみましょう。 そういう時はstringsというコマンドが便利です。これは指定したファイルから4文字以上の繋がったASCII文字を抽出するコマンドです。\nつまりバイナリファイルから4文字以上のASCII文字を片っ端から表示するわけですね。 こんな感じにひたすらにASCII文字が表示されていきます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ strings ./ccache.exe !This program cannot be run in DOS mode. .text P`.data .rdata `@.pdata 0@.xdata 0@.bss .idata .CRT .tls .rsrc B/19 B/31 B/45 B/57 例えばビルドした人を知りたければ、stringsの結果をgrepに渡してあげればわかる可能性があります。 下記の例はMINGW（Windows）なのでパスの形式がC:で始まっています。Linuxの場合は適宜そこを置き換えてください。 C:\\Users\\username\\work\\tmp\\ccache-3.5というようにビルドしたときのパスがあります。usernameのところでユーザ名が判別できてしまいます。\n1 2 3 4 5 6 7 $ strings ./ccache.exe | grep -i \u0026#34;C:[/\\\\]\u0026#34; | sort | uniq C:/Programs/msys64/mingw64/etc C:/Programs/msys64/mingw64/include C:/Programs/msys64/mingw64/x86_64-w64-mingw32/include C:\\Users\\username\\work\\tmp\\ccache-3.5 C:\\repo\\mingw-w64-crt-git\\src\\crt-x86_64-w64-mingw32 このようにして、割と簡単にいろんな情報を抜き出せてしまいます。悪用できてしまいそうですね。\nシンボル情報を削除する ではどう対処すればいいか。不要なシンボル情報を削除すればOKですね。stripというコマンドがそれを実現してくれます。 使い方も簡単。単に実行可能ファイルを渡せばいいだけです。\n1 strip ./ccache.exe こうするとnmコマンドを実行しても下記のように「シンボルが見つかりません」という旨のメッセージが表示されます。シンボル情報の削除に成功していますね。\n1 2 $ nm ./ccache.exe C:\\Programs\\msys64\\mingw64\\bin\\nm.exe: ./ccache.exe: no symbols stringsについては、さすがにすべてのASCII文字を削除するわけにはいかないので、多少は残ります。 例えばprintfで表示するメッセージなんか削除されたら困りますし。ですが、先ほどみたようなビルドパスは削除されます。\n1 strings ./ccache.exe | grep -i \u0026#34;C:[/\\\\]\u0026#34; | sort | uniq これで余計なシンボル情報が削除できていることが確認できましたね。\nまとめ 今回は実行可能ファイルに含まれているシンボル情報による漏洩の危険性と、その削除の仕方について述べました。 上記は基本的な使い方のみの紹介ですので、興味のある方はGNUのマニュアルなどを参照していろいろと遊んでみてください！\n","permalink":"https://nagayasu-shinya.github.io/posts/strip-symbol-information-binary/","summary":"\u003cp\u003e実行可能ファイルのシンボル情報を削除して情報漏えいのリスクを下げる方法を説明します。\u003c/p\u003e","title":"C言語で作成した実行可能ファイルのシンボル情報を削除｜情報漏洩を防ごう"},{"content":"Ankiの登録をGUIで行うのは手間がかかるのでエディタで登録する方法を述べます。\n英単語を覚えるのに苦労していませんか？私は苦労しています。 どうにかして少しでもラクできないかといろいろと調べてみたところ、どうもAnkiというアプリがイケてるという情報をゲットしました。\nいわゆるフラッシュカード（単語カードアプリ）なんですが、出題頻度を忘却曲線に合わせて調整してくれる、 つまり忘れやすい単語は頻繁に出題して忘れにくい単語はたまにしか出題しない、ということをやってくれるアプリです。\nこのAnkiはかなり高機能（発音させたりもできるらしい）なので使いこなすのは骨が折れますが、今回はひとまず凝ったことはせずにシンプルな単語帳を作る方法を解説します。それだけでも忘却曲線に沿って問題を出してくれるので十分に使用できると思います。具体的には次の２つの方法を示します。\nシェアされている単語帳を利用する 自分でベーシックな単語帳を作成する Note\nandroid版やPC版は無料なんですが、なぜかiPhone版は有料で3000円ほどします\u0026hellip;. 結構お高いのですが、個人的にはその値段の価値はあるのではと思います。\nAnkiとは Ankiは名前のまんま、暗記するためのアプリです。単語カードを電子化したものと思っていただければイメージがわくかなと思います。 単語カードとは下記のようなヤツですね。英単語だったら、表に英単語で裏にその日本語訳を書くやつ。中学生や高校生の頃に使った人も多いのでは。\nリンク 単に電子化しただけなら他にもいろんなアプリがありそうですが、このAnkiは忘却曲線にしたがって忘れた頃に同じ問題を出してくれるという優れものです。 簡単なものはしばらく出題されませんが難しいもの（すぐ忘れたもの）は何度もしつこく出題してくれます。 例えば簡単に答えられた問題は30日後、間違えてしまったのは翌日に出題するといった感じです。これにより効率的に記憶していける仕組みです。\n詳細について知りたい方はRemembering is easier with Ankiの「Spaced Repetition」の章を見てみるといいかもしれません。\n今回はPCとスマホと両方で使用する場合を想定しています。PCで単語帳を作成して、スマホで隙間時間に暗記するといったユースケースを想定しています。\nAnkiのインストールとAnkiWebへの登録 まずはPCとスマホそれぞれにAnkiをインストールします。さらにそれらのデータ（単語帳や学習記録など）の同期を取るためにAnkiWebにユーザー登録します。 特に難しいことはありませんが、一応、インストールの仕方などを書いておきます。\nPCへのインストール 公式サイトAnkiWeb からインストーラをダウンロードしてダブルクリックするだけです。\nWindows/Linux／Mac OS X それぞれにインストーラーがあります。 お使いの環境に合わせてダウンロード、インストールしてください。\nスマホへのインストール これも特に難しいことはありません。「Anki」で検索してアプリをインストールするだけです。 下記はiPhoneの場合です。Androidでも同じだと思います。似たような名前のアプリと間違えないようにお気をつけください。\nAnkiWebへのユーザー登録 各デバイス間でデータを同期するためには、AnkiWebへの登録が必要です（無料）。 AnkiWebからSignUpしてください。\nこんな感じの画面にてメールアドレスとパスワードを入れるだけですね。\n単語帳（Deck/デッキ）の作り方 単語帳のことをAnkiではDeck（デッキ）といいます。 このDeckの作り方を説明します。これはPCでの作業です。\nシェアされている単語帳を使う 実はAnkiWebには、作成したデッキをみんなとシェアする機能があります。これを利用すれば自分でデッキ（単語帳）を作る必要はありません。 自分で作るのは面倒という方はこれを利用するといいと思います。\n今回は超有名な英単語帳「[DUO 3.0]を例に説明します。\nリンク Duo だけやっていればTOEICで730取れる！と豪語する方もいらっしゃるくらいに有名です。 あと登場人物のボブの扱いがやたら悪いことでも有名です。ちょくちょく下記のような例文が出てきます。ボブ\u0026hellip;..かわいそう。\nボブはひどく取り乱していて、現実と虚構の区別がほとんどできなかった ボブが「それには反対だ！」と言って会話に割り込んできたけれども、誰も耳を貸さなかった 閑話休題。\nまず、AnkiWebにログインします。\n次に、「Get Shared Decks」ボタンを押します。\nする下図の赤枠のような検索窓が表示されます。今回はDuoを使いたいので、Duoで検索してみてください。\n下記のように複数のデッキがヒットすると思います。この中からお好きなものを使えばOKです。今回は例として一番上に表示されたものを使用してみます。\n「Front」というのがカードの表面に該当します。 つまり問題ですね。「Back」というのがカードの裏面に該当します。つまり回答です。 「Tags」というのは単語帳管理に使えるラベルですが、今回は気にしなくてOKです。 「Download」ボタンを押すと単語帳データをダウンロードできます。拡張子は.apkgとなっているかと思います。\n次は、ダウンロードしたデッキ（.apkgファイル）を読み込みます。まずAnkiを起動してください。 起動すると下記のようなウィンドウが表示されると思いますので、「ファイルを読み込む」ボタンをクリックしてください。\n先ほどダウンロードしたデッキ（.apkgファイル）を選択してください。\nこれでデッキの作成は終わりです。下記のようにデッキが作成されていればOKです。\n自分でデッキ（単語帳）を作る DUO 3.0くらいにメジャーならデッキがシェアされていますが、シェアされていない単語帳もたくさんあります。\nそこで自分でデッキ（単語帳）を作る方法を解説します。流れとしては、まずはGUIにてデッキのデータを作り、そのあとエディタで単語データを追加していきます。全部GUIでやることもできるんですが、それだととても手間がかかるのでエンジニアっぽくエディタで作れるような手順を示します。\n例として今回は下記の単語帳「新TOEIC TEST 出る順で学ぶボキャブラリー990」のデッキを作ってみます。\nリンク 内容は下記のような感じです。\nデッキの新規作成 まずはベースとなるデッキ（単語帳）を作成します。あとから単語は追加して行きますので、まずは空で作成します。\nAnkiを立ち上げます。そして「単語帳を作成」をクリックします。\n新規作成する単語帳の名前を聞かれるので、好きな名前をつけます。ここでは「新TOEIC TEST 出る順で学ぶボキャブラリー990」としました。\nこれで空のデッキが追加されました。\nGUIで単語を登録する 次に、単語を登録します。下記のように「追加」ボタンをクリックします。\n下記のように単語を追加するウィンドウが表示されます。赤枠のところを入力してください。 「Front」はカードの表面、つまり問題です。「Back」はカードの裏面、つまり回答です。 「Tags」というのは単語帳管理に使えるラベルです、なんでもいいのですが今回は付属のCDのトラック番号を書いておきました。\nこれでデッキに単語が１つ登録できました。\nデッキをファイルに書き出す 次にこのデッキのデータをファイルに書き出します。現時点は単語は先ほど登録した１つだけですね。\n「テキストファイル形式のノート（*.txt）」を選択して任意のディレクトリに保存してください。 Mac OS Xならデフォルトで下記の場所に保存されます。 /Users/username/Library/Application Support/Anki2/\n保存したファイルをエディタで開くと下記のようになっているはずです。Front、Back、Tagsの順番で、タブ区切りで保存されています。\n1 product 製品 track01 エディタで単語を登録していく 登録単語を増やしたい場合、このファイルに追記していけばOKです。 デフォルトではタブ区切りですが、セミコロンなどでもOKです。この例では、タブはみづらいのでコロン区切りにしてみました。\n1 2 3 4 5 6 7 8 9 10 product : 製品 : track01 employ : 雇う : track01 business : 会社 : track01 customer : 客 : track01 montyly : 毎月 : track01 report : 報告書 : track01 schedule : 予定に入れる : track01 mail : 郵送する : track01 receive : 受け取る : track01 visitor : 観光客 : track01 さて、ファイルを更新して保存したら、再度ファイルを読み込みます。\n更新したファイルを選択します。\nすると下記のようなウィンドウが開くはずです。赤枠で示したように３つのフィールドが認識されていればOKです。 「Front」「Back」「Tags」の３つですね。\nもし下記のようにフィールドが１つしか認識されていない場合は、フィールド区切り文字を設定する必要があります。 下図の「タブで区切ったフィールド」というところをクリックしてください。\nすると下記のような区切り文字の設定ウィンドウが開きます。 今回の例ではコロンを区切り文字として使用したので:を設定してください。 これでフィールド３つが認識されるはずです。\nあとは「読み込む」ボタンをクリックすれば、追記した単語データが読み込まれます。\nデッキの単語を確認 ここまでで単語が複数登録できているはずです。それを確認しましょう。まず「ブラウザー」をクリックします。\n下記のようなウィンドウが表示されます。 左ペインで今回登録したデッキ「新TOEIC TEST 出る順で学ぶボキャブラリー990」を選択してください。 右上ペインに赤枠で囲ったように今回登録した単語たちが表示されていればOKです。\n最後にAnkiWebと同期するのを忘れないようにしましょう。下図の赤枠で囲ったボタンを押せばOKです。 これでAnkiWebにもデッキが反映されました。\n登録した単語をスマホで勉強してみる 動作確認も兼ねて、上記で登録した単語をスマホでみてみましょう。スマホのAnkiアプリを起動します（下記の例はiPhoneです）。 まずはAnkiWebからデッキをダウンロードします。右下の「Syncronize」を押してください。するとAnkiWebと同期されます。 これで作成したデッキが使えるようになったはずです。\n試しにデッキ名のとこを押して単語をめくってみてください。 下記のように登録した単語が表示されればOKです！お疲れ様でした！！\nまとめ 今回は英単語の暗記の強い味方「Anki」というアプリについて説明しました。 Ankiはいわゆるフラッシュカードですが、忘却曲線にしたがって出題頻度を調整してくれるのが売りです。 フラッシュカードですので単語を登録する必要があります。 登録はGUIでも可能ですが、それだと大変なので設定ファイルをエディタで編集して登録する方法を説明しました。 わたしと同じ英語苦手なかたの英語学習の一助になれば幸いです！\n","permalink":"https://nagayasu-shinya.github.io/posts/anki-flashcard-deck-creation/","summary":"\u003cp\u003e\u003ca href=\"https://ja.wikipedia.org/wiki/Anki\"\u003eAnki\u003c/a\u003eの登録をGUIで行うのは手間がかかるのでエディタで登録する方法を述べます。\u003c/p\u003e","title":"英単語暗記アプリAnkiにて英単語をGUIを使わずにエディタで登録する方法"},{"content":"一般的にテキストファイルの差分は diff などで確認できますが、MS Word には標準で差分を表示する機能があります。 フォントサイズなども比較できるこの機能を紹介します。\nMS Wordの文章比較 みなさん、MS Word 使っていますか？ 最近は Markdown なんかで資料を書くことも多いと思いますが、対外的に出す正式な仕様書などはやはり MS Word で、というところも多いかなと思います。仕様書となればもちろんGitやSVNなどでバージョン管理していることでしょう。 このときに困るのは、MS Wordの各リビジョン間の差異の確認です。 ソースコードなら diff コマンドなんかをつかえば差分なんか即わかるのですが、 残念ながら MS Word には diff はつかえません。 かといって目Grep（目視）で変更点を探すのはIT技術者として敗北感にさいなまされます。 なによりめんどくさいし見落とす可能性大です。そこで今回は、意外に知られていない MSWordの標準機能である「文書の比較」をする機能について説明します。 標準機能ですので外部ツールも必要ありませんし、作成者などのメタ情報およびフォントサイズなどもチェックできる優れものです。\nMS Word でのファイル比較（差分表示）の方法 今回は MS Word 2013 を例に説明します。 他のバージョンでも表示がすこしちがうだけで基本は同じです。 また、元のファイルを「テンプレート.docx」、修正後のファイルを「テンプレートv2.docx」としておきます。 変更箇所は下図の赤線の場所です。\nでは差分を表示する方法をみていきます。 まず、元のファイル「テンプレート.docx」を開きます。そして下図のように「ファイル」→「校閲」→「比較」→「比較」という順番でクリックします。\nすると、下記のように「文書の比較」というウィンドウが表示されます。 左側に元のファイル、右側に修正後のファイルを指定してください。\n下記のようなウィンドウが表示されると思います。左は具体的な変更内容です。 真ん中は比較結果です。右の上段は元の文章、右の下段は変更後の文章です。 このように一目で変更箇所がわかるように表示されます。便利ですね！\nFYI: TortoiseSVN での MS Word 差分表示 ソースコードなどのテキストは WinMerge で差分表示することが多いかなと思います。 ですがバイナリファイルは、WinMergeでは基本的に差異があるかどうかしか表示しません。 そこで以前は、MS Wordの差分を確認するために WinMerge とそのプラグインのxdocdiff を組み合わせる必要がありました。 MS Wordのファイルをテキストコードに変換してから、それらを WinMergeで比較するという感じです。 ですがその方法だとメタ情報やフォント情報などが失われるため、できれば上記で説明したMS Word の比較機能を使いたいところです。 しかし現在はとくに何もしなくても、 TortoseSVN が勝手に MS Wordの比較機能を使って差分を表示してくれます。 下記のようなスクリプトを使っていい感じに上記のMS Word の比較機能を呼び出してくれます。\nちなみにTortoiseSVN で MS Wordのリビジョン比較をした場合、下記のようになります。 ちゃんと比較機能がつかわれていますね！\nまとめ 今回は意外に知られていない、MS Wordのファイル比較（差分表示）の機能をご紹介しました。 目Grepで修正箇所を頑張って探さなくても、この機能を使えばさくっと差異を表示できます。\nもしWordを使いこなしたいなら下記の本が詳しいです。\nリンク ","permalink":"https://nagayasu-shinya.github.io/posts/word-document-comparison/","summary":"\u003cp\u003e一般的にテキストファイルの差分は \u003ccode\u003ediff\u003c/code\u003e などで確認できますが、MS Word には標準で差分を表示する機能があります。\nフォントサイズなども比較できるこの機能を紹介します。\u003c/p\u003e","title":"MS Word でファイルを比較して差異を表示する"},{"content":"Proxy環境下では、WSL上からネットにアクセスしたりapt-getしたりするには、別途WSL側にもProxy設定が必要となります。今回はその設定方法を説明します。\nNote\nDocker のプロキシ設定についてはDocker の Proxy初期設定の記事もご参照ください。\nProxy未設定時のエラー Proxyを使っている環境でWSLでのProxy設定をしていない場合、例えばsudo apt updateを実行すると下記のようなエラーが出ます。 ぱっとみ、DNS関係のエラーにも見えますが、Proxy未設定でもこのエラーが出ます。 （DNSの問題でもおそらく同じようなエラーが出ると思いますが、今回はProxyに絞って説明します）\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ sudo apt update Ign:1 http://archive.ubuntu.com/ubuntu xenial InRelease Ign:2 http://security.ubuntu.com/ubuntu xenial-security InRelease Ign:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease Err:4 http://security.ubuntu.com/ubuntu xenial-security Release Something wicked happened resolving \u0026#39;security.ubuntu.com:http\u0026#39; (-5 - No address associated with hostname) Ign:5 http://archive.ubuntu.com/ubuntu xenial-backports InRelease Err:6 http://archive.ubuntu.com/ubuntu xenial Release Something wicked happened resolving \u0026#39;archive.ubuntu.com:http\u0026#39; (-5 - No address associated with hostname) Err:7 http://archive.ubuntu.com/ubuntu xenial-updates Release Something wicked happened resolving \u0026#39;archive.ubuntu.com:http\u0026#39; (-5 - No address associated with hostname) Err:8 http://archive.ubuntu.com/ubuntu xenial-backports Release Something wicked happened resolving \u0026#39;archive.ubuntu.com:http\u0026#39; (-5 - No address associated with hostname) Reading package lists... Done E: The repository \u0026#39;http://security.ubuntu.com/ubuntu xenial-security Release\u0026#39; does not have a Release file. N: Updating from such a repository can\u0026#39;t be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. E: The repository \u0026#39;http://archive.ubuntu.com/ubuntu xenial Release\u0026#39; does not have a Release file. N: Updating from such a repository can\u0026#39;t be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. E: The repository \u0026#39;http://archive.ubuntu.com/ubuntu xenial-updates Release\u0026#39; does not have a Release file. N: Updating from such a repository can\u0026#39;t be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. E: The repository \u0026#39;http://archive.ubuntu.com/ubuntu xenial-backports Release\u0026#39; does not have a Release file. N: Updating from such a repository can\u0026#39;t be done securely, and is therefore disabled by default. N: See apt-secure(8) manpage for repository creation and user configuration details. proxyの設定の確認 WSLのプロキシ設定は、基本的に現在Windows側にて設定されているものを使えばOKです。 そこでまずは現状のプロキシ設定を確認します。 まずはじめに「コントロールパネル」を開きます。そのなかの「インターネットオプション」を選択します。\n次に、「接続」タブを選択し「LANの設定」をクリックします。 そうするとProxyなどの設定をするウィンドウが開きます。そこにProxyのアドレスとポート番号が書いてありますのでそれをメモします。\nこれでプロキシ設定の確認は終わりです。\nPAC を使っている場合 基本的に上記の方法でいいのですがもしPACを使っている場合はひと手間いります。 もし上記の右の設定画面にて「自動構成スクリプトを使用する」にチェックが入っていればPACをつかっています。 その場合は WSLでのProxy設定方法｜PACファイルでも を参考にして見てください。\nhttp_proxy変数の設定 http_proxyとhttps_proxyという環境変数を設定する必要があります。 ホームディレクトリ直下の .bashrc に下記のように設定を書いておけば良いと思います。 これでログイン時に自動で設定されます。 proxy-host proxy-portには、先ほど確認したプロキシのアドレスとポート番号を入れてください。 usernameとpasswordは、WSLのではなくProxyのユーザ名とパスワードです。\n1 2 3 4 5 6 export ftp_proxy=http://username:password@proxy-host:proxy-port export http_proxy=http://username:password@proxy-host:proxy-port export https_proxy=http://username:password@proxy-host:proxy-port export FTP_PROXY=http://username:password@proxy-host:proxy-port export HTTP_PROXY=http://username:password@proxy-host:proxy-port export HTTPS_PROXY=http://username:password@proxy-host:proxy-port apt.confの設定 次にapt.confファイルの設定です。/etc/apt/apt.confにて下記を設定してください。 もし/etc/apt/apt.confがなければ新規に作成してください。行末の;を忘れないようにご注意ください。\n1 2 3 Acquire::ftp::proxy \u0026#34;http://username:password@proxy-host:proxy-port\u0026#34;; Acquire::http::proxy \u0026#34;http://username:password@proxy-host:proxy-port\u0026#34;; Acquire::https::proxy \u0026#34;http://username:password@proxy-host:proxy-port\u0026#34;; これで設定は終わりです。WSLターミナルをいったん終了して、再度起動してみてください。 sudo apt updateが成功すればOKです。 OK時は下記のような感じになります。\n1 2 3 4 5 6 7 8 9 10 $ sudo apt update Hit:1 http://archive.ubuntu.com/ubuntu xenial InRelease Get:2 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [107 kB] Get:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB] Fetched 323 kB in 1s (181 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done All packages are up to date. curl の設定 .bashrc にプロキシ設定を書いておけばこれは不要かと思いますが、参考までに書いておきます。 下記のような感じで .curlrc に設定をかけばOKです。\n1 echo \u0026#39;proxy=\u0026#34;http://username:password@proxy-host:proxy-port\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.curlrc /etc/environment これも無くても大丈夫かと思いますが、参考までに書いておきます。 /etc/environment の設定です。下記のように追記すればOKです。\n1 2 3 4 5 6 sudo bash -c \u0026#39;echo \u0026#34;http_proxy=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; sudo bash -c \u0026#39;echo \u0026#34;https_proxy=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; sudo bash -c \u0026#39;echo \u0026#34;ftp_proxy=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; sudo bash -c \u0026#39;echo \u0026#34;HTTP_PROXY=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; sudo bash -c \u0026#39;echo \u0026#34;HTTPS_PROXY=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; sudo bash -c \u0026#39;echo \u0026#34;FTP_PROXY=http://username:password@proxy-host:proxy-port\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; まとめ 今回はWSLのProxy設定の方法を説明しました。~/.bashrc と /etc/apt/apt.conf に設定を追加すればOKです。ご参考になれば幸いです。\nNote\nDocker のプロキシ設定については Docker の Proxy初期設定 の記事もご参照ください。\n","permalink":"https://nagayasu-shinya.github.io/posts/proxy-configuration-wsl/","summary":"\u003cp\u003eProxy環境下では、WSL上からネットにアクセスしたりapt-getしたりするには、別途WSL側にもProxy設定が必要となります。今回はその設定方法を説明します。\u003c/p\u003e","title":"WSLのProxy設定方法"},{"content":"Arduinoのブートローダが破損した場合の修復方法を説明します。格安互換機などで動作がおかしくなった場合に有効です。\nArduinoを使っているときに、ときどき動作がおかしくなってしまうときがありますよね。 自分の作ったスケッチがバグっているなら、スケッチを修正してファームウェアを再度ダウンロードすればいいのですが、まれにブートローダ(Bootloader)がおかしくなってしまう場合があります。 純正品ではあまりないと思いますが、格安の互換機でちょっと変則的な使い方をするとときどき発生します。\nブートローダーがやられると、通常のバグとは全く異なる動作をしてしまいなにがなんだかわからない状況に陥ってしまいます。 そのような**「Arduinoがなんかおかしくなっちゃった！」というかたのためにブートローダを修復する方法を記載します**。 「なんかわからんけどそもそも全然動かん！」というかたは目を通して見ていただければなと思います。\n内容としては、公式サイトの Arduino as ISP and Arduino Bootloaders をやって見ただけという感じですので、 英語が得意なかたは公式の方を見ていただいた方が早いかもしれません。\nArduinoのブートローダ Arduinoのブートローダは電源オン時にユーザーのスケッチをロードする（実行する）以外に、「PCと接続する」「スケッチをROMに書き込む」などの基本的な機能も提供しています。 つまり、ブートローダが破損すると「PCとの接続ができない、COMポートから見えない、もしくは接続が不安定になる」「コンパイルしたスケッチをダウンロードしようとしたらエラーが出てしまう」などの症状が発生します。\nブートローダの修復に必要なもの ブートローダはROM（EEPROM）に格納されているため、PCからは書き換えできません。 例えばArduino用ブートローダ/スケッチライタキットのようなキットを使えば書き換え可能です。\nこのようなキットは、ブートローダをガチャガチャいじるようなマニアな人は持っているかもしれませんが、標準のブートローダで事足りるかたは普通持っていないかと思います。 また、ブートローダ復旧のためにキットを買うのもなんだか躊躇してしまうかもしれません。そこで今回はライタキットでなく、普通のArduinoをライタ代わりに使います（つまりブートローダを書き換えるために、もう1枚正常動作するArduinoを使います）。\nArduinoを2枚持っているかたもあまり多くはないかもしれませんが、値段の安さと、ライタと違って通常使用で予備として使えることを考えれば、ライタよりも普通のArduinoを代用した方がリーズナブルかなと思います。 今回は例として、下記のArduinoUno 互換品を使います。ワンコインで買えちゃうのでお財布に優しいです。もちろん純正でもOKです。\nリンク Arduino をブートローダのライタ(ISP:In-circuit Serial Programmer)として使う ライタ側のArduinoUNO の準備 まず、ブートローダが正常に動く方、つまりライタ側のArduinoをPCと接続します。 そしてArduino IDEを起動して、「ArduinoISP」というスケッチを開きます。下記の図を参照してください。\n次に、そのスケッチをArduinoにダウンロードします。通常通りにボタンをポチッとすればOKです。\nこれでこのArduinoはブートローダのライタとして動作可能になりました。\nライタ側のArduinoと書き込まれる側のArduinoの接続 まず、念のために両方のArduinoをPCから外しておきます（電源を供給していな状態にしておきます）。そしてライタ側のArduinoと書き込まれる側のArduinoを接続します。 通常ブートローダを書き込む際はICSPコネクタを使います。もちろんこれを使ってもいいのですが、ライタ側のArduinoと書き込まれる側のArduinoが同じ製品ならサクッと各SPIピン同士をつなげてしまう方が楽です、ICSPのピン配置をチェックするめんどうがないので。 今回は例としてライタ側、書き込まれる側ともにArduinoUNOをしています。その場合の配線は下記のようにします。全部で6本です。\nNote\n基本は「同じピン同士」を接続します。例外は1つだけで、ライタ側の10ピンを、書き込まれる側のRSTに接続します。\nNo. ライタ側（UNO） 書き込まれる側（UNO） 信号/役割 1 10ピン RST リセット 2 GND GND GND 3 5V 5V 電源 4 11ピン 11ピン MOSI 5 12ピン 12ピン MISO 6 13ピン 13ピン SCK 配線したらこんな感じです（公式サイトより抜粋）。すごく簡単ですね。\n実際の基板を配線するとこんな感じになります。今回は純正品でなく 純正品でないですが、純正品でも同じです。\nこれで配線は完了です。簡単ですね。\nブートローダの書き込み いよいよブートローダの修復です。まず、ライタ側のArduinoUNOをPCと接続します。書き込まれる側はPCとは接続しません。配線にて5Vをつないでいるので電源はライタ側のArduinoから供給されます。 次に Arduino IDE　を起動してメニュー「ツール」から「書込装置」を設定します。「Arduino as ISP」というものを選択してください。 似たような名前のものがあるので間違えないように注意してください。「ArduinoISP」ではありません。 ここまでくればあとは、「ブートローダを書き込む」をポチッとすればOKです。下記の図を参考にして見てください。\n書き込みには数分くらいかかるかもしれません。IDE上に下記のようなログが出るはずです。\nログを展開 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 C:\\Programs\\arduino\\hardware\\tools\\avr/bin/avrdude -CC:\\Programs\\arduino\\hardware\\tools\\avr/etc/avrdude.conf -v -patmega328p -cstk500v1 -PCOM3 -b19200 -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDE:m -Ulfuse:w:0xFF:m avrdude: Version 6.3, compiled on Jan 17 2017 at 12:00:53 Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ Copyright (c) 2007-2014 Joerg Wunsch System wide configuration file is \u0026#34;C:\\Programs\\arduino\\hardware\\tools\\avr/etc/avrdude.conf\u0026#34; Using Port : COM3 Using Programmer : stk500v1 Overriding Baud Rate : 19200 AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK serial program mode : yes parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 ByteDelay : 0 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00 Programmer Type : STK500 Description : Atmel STK500 Version 1.x firmware Hardware Version: 2 Firmware Version: 1.18 Topcard : Unknown Vtarget : 0.0 V Varef : 0.0 V Oscillator : Off SCK period : 0.1 us avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.01s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: erasing chip avrdude: reading input file \u0026#34;0x3F\u0026#34; avrdude: writing lock (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of lock written avrdude: verifying lock memory against 0x3F: avrdude: load data lock data from input file 0x3F: avrdude: input file 0x3F contains 1 bytes avrdude: reading on-chip lock data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 1 bytes of lock verified avrdude: reading input file \u0026#34;0xFD\u0026#34; avrdude: writing efuse (1 bytes): C:\\Programs\\arduino\\hardware\\tools\\avr/bin/avrdude -CC:\\Programs\\arduino\\hardware\\tools\\avr/etc/avrdude.conf -v -patmega328p -cstk500v1 -PCOM3 -b19200 -Uflash:w:C:\\Programs\\arduino\\hardware\\arduino\\avr/bootloaders/optiboot/optiboot_atmega328.hex:i -Ulock:w:0x0F:m Writing | ################################################## | 100% 0.02s avrdude: 1 bytes of efuse written avrdude: verifying efuse memory against 0xFD: avrdude: load data efuse data from input file 0xFD: avrdude: input file 0xFD contains 1 bytes avrdude: reading on-chip efuse data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 1 bytes of efuse verified avrdude: reading input file \u0026#34;0xDE\u0026#34; avrdude: writing hfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of hfuse written avrdude: verifying hfuse memory against 0xDE: avrdude: load data hfuse data from input file 0xDE: avrdude: input file 0xDE contains 1 bytes avrdude: reading on-chip hfuse data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 1 bytes of hfuse verified avrdude: reading input file \u0026#34;0xFF\u0026#34; avrdude: writing lfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of lfuse written avrdude: verifying lfuse memory against 0xFF: avrdude: load data lfuse data from input file 0xFF: avrdude: input file 0xFF contains 1 bytes avrdude: reading on-chip lfuse data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 1 bytes of lfuse verified avrdude done. Thank you. avrdude: Version 6.3, compiled on Jan 17 2017 at 12:00:53 Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ Copyright (c) 2007-2014 Joerg Wunsch System wide configuration file is \u0026#34;C:\\Programs\\arduino\\hardware\\tools\\avr/etc/avrdude.conf\u0026#34; Using Port : COM3 Using Programmer : stk500v1 Overriding Baud Rate : 19200 AVR Part : ATmega328P Chip Erase delay : 9000 us PAGEL : PD7 BS2 : PC2 RESET disposition : dedicated RETRY pulse : SCK serial program mode : yes parallel program mode : yes Timeout : 200 StabDelay : 100 CmdexeDelay : 25 SyncLoops : 32 ByteDelay : 0 PollIndex : 3 PollValue : 0x53 Memory Detail : Block Poll Page Polled Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- --------- eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00 calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00 signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00 Programmer Type : STK500 Description : Atmel STK500 Version 1.x firmware Hardware Version: 2 Firmware Version: 1.18 Topcard : Unknown Vtarget : 0.0 V Varef : 0.0 V Oscillator : Off SCK period : 0.1 us avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.02s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: NOTE: \u0026#34;flash\u0026#34; memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file \u0026#34;C:\\Programs\\arduino\\hardware\\arduino\\avr/bootloaders/optiboot/optiboot_atmega328.hex\u0026#34; avrdude: writing flash (32768 bytes): Writing | ################################################## | 100% 0.00s avrdude: 32768 bytes of flash written avrdude: verifying flash memory against C:\\Programs\\arduino\\hardware\\arduino\\avr/bootloaders/optiboot/optiboot_atmega328.hex: avrdude: load data flash data from input file C:\\Programs\\arduino\\hardware\\arduino\\avr/bootloaders/optiboot/optiboot_atmega328.hex: avrdude: input file C:\\Programs\\arduino\\hardware\\arduino\\avr/bootloaders/optiboot/optiboot_atmega328.hex contains 32768 bytes avrdude: reading on-chip flash data: Reading | ################################################## | 100% -0.00s avrdude: verifying ... avrdude: 32768 bytes of flash verified avrdude: reading input file \u0026#34;0x0F\u0026#34; avrdude: writing lock (1 bytes): Writing | ################################################## | 100% 0.03s avrdude: 1 bytes of lock written avrdude: verifying lock memory against 0x0F: avrdude: load data lock data from input file 0x0F: avrdude: input file 0x0F contains 1 bytes avrdude: reading on-chip lock data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 1 bytes of lock verified avrdude done. Thank you. なにやら最後にベリファイしてサンキューて書いてあるので、大丈夫そうですね。 これでブートローダの書き込みは完了です。お疲れ様でした。不具合の原因がブートローダだったなら、これで解決するはずです！\nまとめ ArduinoUNO（の互換機）を例に、ブートローダの修復方法を説明しました。基本的に公式サイト通りにやれば問題ありません。基板さえあればブートローダの修復は簡単なので、ハードウェアのチェックをする前にダメ元で試してみるのもありかなと思います。ブートローダライタキットを買うよりも安いですしね。\n","permalink":"https://nagayasu-shinya.github.io/posts/arduino-bootloader-repair/","summary":"\u003cp\u003eArduinoのブートローダが破損した場合の修復方法を説明します。格安互換機などで動作がおかしくなった場合に有効です。\u003c/p\u003e","title":"ArduinoのBootloaderを修復する"},{"content":"Arduino IDE でのビルドを速くするためにccacheというc/c++向けのコンパイル高速化ツールを使って高速化する方法をご紹介します。\nccacheのインストール まずは ccache をインストールします。 C/C\u0026#43;\u0026#43;のコンパイルを高速化する｜ccacheの記事にてccacheの簡単な説明とインストール方法（Windows、Linux、Mac OS X）を書いています。 インストールは簡単ですのでサクッと終わると思います。\nArduino IDE の前準備 次に、Arduino IDEの前準備をします。Arduino IDEのデフォルトのコンパイルの挙動は「ランダムな名前でディレクトリを作りそこに.oファイルを出力する。 かつ、その出力先をコマンドオプションで指定する」という（個人的には）あまり使いやすいものではない設定になっています。 その挙動ではccacheを動かすのは大変なので、Arduino IDEのビルドを速くする｜オブジェクトファイルの出力先を固定するの記事を参考に出力ディレクトリを固定してください。\nArduino IDE にてccacheを使う設定 この時点でccacheを使う準備は整いました。あとはArduino IDE設定ファイルを少し書き換えるだけです。 具体的には、コンパイラのオプションが書かれているplatform.txtを修正します。 コンパイラの設定が書かれているので使用するマイコンによってファイルがある場所が異なります。\nここでは例として、Atmel AVR マイコンが搭載されているArduino UNO を例に説明します。 Arduino Nano も同マイコンなので全く同じ手順です。 「ほかのマイコンが載ってるよ！」という方も、おいてあるフォルダは違えどplatform.txtという同じなまえでどこかにあるはずなので、探してみてください。\nWindowsでc:\\Programs\\arduino\\に Arduino IDE をインストールした場合は、設定ファイルは下記のc:\\Programs\\arduino\\hardware\\arduino\\avr\\platform.txt にあります。 LinuxやMac OS X もだいたい同じような場所にあるはずです。Arduinoのあるフォルダからみてhardware\\arduino\\avr\\platform.txtにあると思います。\nplatform.txtを見つけたら、お好きなエディタで開いてください。そしてコンパイラオプションを設定しているところを探してください。 recipe.c.o.pattern recipe.cpp.o.patternで検索するとヒットするはずです。 ここでいうrecipe(レシピ)とは、Makefileで言えばパタンルールに該当します。「.c から .oを作成する方法」くらいの意味ですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # AVR compile patterns # -------------------- ## Compile c files recipe.c.o.pattern=\u0026#34;{compiler.path}{compiler.c.cmd}\u0026#34; {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} \u0026#34;{source_file}\u0026#34; -o \u0026#34;{object_file}\u0026#34; ## Compile c++ files recipe.cpp.o.pattern=\u0026#34;{compiler.path}{compiler.cpp.cmd}\u0026#34; {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} \u0026#34;{source_file}\u0026#34; -o \u0026#34;{object_file}\u0026#34; ccache を使うには、このレシピにccacheを付け加えるだけです。 必ずコマンドの先頭につけてくださいね。下記の例を参考にしてください。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # AVR compile patterns # -------------------- ## Compile c files recipe.c.o.pattern=ccache \u0026#34;{compiler.path}{compiler.c.cmd}\u0026#34; {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} \u0026#34;{source_file}\u0026#34; -o \u0026#34;{object_file}\u0026#34; ## Compile c++ files recipe.cpp.o.pattern=ccache \u0026#34;{compiler.path}{compiler.cpp.cmd}\u0026#34; {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} \u0026#34;{source_file}\u0026#34; -o \u0026#34;{object_file}\u0026#34; Arduino IDE にてccacheが動いているか確認 実際にArduino IDEで任意のスケッチをビルドしてみます。下記の赤枠のようにccacheが呼ばれていたら成功です！！\nccacheの統計情報にてccacheが動いているか確認 念のためccacheの統計情報（キャッシュヒット率などの情報）をみて、ちゃんとccacheが実行されているか確認しておきましょう。 今回はWindows にて解説しますが、Linuxでも Mac OS Xでも同じです。\nまた、Arduino IDEのビルドを速くする｜オブジェクトファイルの出力先を固定するで作った出力ディレクトリはC:\\Users\\username\\AppData\\Local\\Temp\\arduino_buildとしおきます。 まず、確認がしやすいようにccacheのキャッシュをクリアしておきます。\n1 C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;ccache -c -C -z この状態で統計情報を表示させると、下記のようにヒット数、ヒット率、ミスヒット数など全部が0になっているはずです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;ccache -s cache directory C:\\Users\\username\\AppData\\Roaming/.ccache primary config C:\\Users\\username\\AppData\\Roaming/.ccache/ccache.conf secondary config (readonly) C:/Programs/msys64/mingw64/etc/ccache.conf stats zero time 04/14/21 01:39:37 cache hit (direct) 0 cache hit (preprocessed) 0 cache miss 0 cache hit rate 0.00 % cleanups performed 0 files in cache 0 cache size 0.0 kB max cache size 5.0 GB この状態で、Arduino IDEにて任意のスケッチをビルドしてみてください。 そして再度、ccacheの統計情報を表示させてみてください。 スケッチによると思いますがミスヒット数（cache miss）が増えているはずです。 最初の1回目のビルドはキャッシュが空っぽなのでキャッシュヒットしようがありませんので、期待した動作ですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;ccache -s cache directory C:\\Users\\username\\AppData\\Roaming/.ccache primary config C:\\Users\\username\\AppData\\Roaming/.ccache/ccache.conf secondary config (readonly) C:/Programs/msys64/mingw64/etc/ccache.conf stats zero time 04/14/21 01:39:37 cache hit (direct) 0 cache hit (preprocessed) 0 cache miss 2 cache hit rate 0.00 % cleanups performed 0 files in cache 74 cache size 392.2 kB max cache size 5.0 GB さらにもう一度ビルドすると、出力ディレクトリの.oファイルが普通に使われるだけなので出力ディレクトリの中身を削除してしまいましょう。 (エクスプローラーからザクっとディレクトリごと消しちゃってももちろんOKです。とにかく出力ディレクトリの.oを消せばOKです）\n1 2 C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;cd arduino_build C:\\Users\\username\\AppData\\Local\\Temp\\arduino_build\u0026gt;del /s/q * .oファイルを全部消したところで、再度、 Arduino IDEにてビルドしてみましょう。 普通ならフルビルドが始まるところですが、先ほどccacheにてキャッシングしているので、今回はコンパイルは実際は行いません。 すぐにビルドも終わるはずです。\nさて、ではccacheの統計情報をみてみましょう。今回はミスヒット(cache miss)数は増えていませんね。 その代わりキャッシュヒット数（direct, preprocessed)が増えています。 つまりキャッシュがヒットしているということですね。このようにキャッシュヒット数が増えていることが確認できればOKです！！\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;ccache -s cache directory C:\\Users\\username\\AppData\\Roaming/.ccache primary config C:\\Users\\username\\AppData\\Roaming/.ccache/ccache.conf secondary config (readonly) C:/Programs/msys64/mingw64/etc/ccache.conf stats zero time 04/14/21 01:39:37 cache hit (direct) 24 cache hit (preprocessed) 1 cache miss 25 cache hit rate 50.00 % cleanups performed 0 files in cache 74 cache size 392.2 kB max cache size 5.0 GB この例くらいの規模ではファイル数が少ないのであまり恩恵を感じられないかもしれませんが、ファイル数が増えれば増えるほど効果は増していきますよ！\nまとめ 今回は、c/c++ コンパイル高速化ツール ccache を Arduino IDEでも使えるようにすることで、コンパイルを高速化する方法をご紹介しました。これで開発が効率化できるはずです！ Arduinoくらいの規模だとビルド時間は軽視されがちですが、ビルドは何度もするので、必ず役に立ちますよ！\n追記：さらに高速化するためにCCACHEを使う方法があります。 Arduino IDEのビルドを速くする｜オブジェクトファイルの出力先を固定するの記事をご参考ください！\n","permalink":"https://nagayasu-shinya.github.io/posts/arduino-build-cache-ccache/","summary":"\u003cp\u003eArduino IDE でのビルドを速くするために\u003ca href=\"https://ccache.dev\"\u003eccache\u003c/a\u003eというc/c++向けのコンパイル高速化ツールを使って高速化する方法をご紹介します。\u003c/p\u003e","title":"Arduinoでccacheを使ってビルドを高速化！"},{"content":"最近はマイコンも多機能になってきて、ビルド時間もバカにならなくなってきています。 そこで今回はC/C++のコンパイルを爆速にするccacheというツールをご紹介します。\nビルド時間は短いほうが正義 開発途中は単純化すると「コード修正」→「単体テスト」→「デバッグ」のサイクルの繰り返しとなるかと思います。 このサイクルにはビルドという作業が必要です。もし仮にビルドに30分かかるとしたら、1営業日に最大16回しかこのサイクルを回せんません（8時間/1営業日と仮定）。 16回でバグを全部なくせ、というのは結構しんどいですよね。\nもしこのビルド時間が10倍速くになればどうでしょうか。最大で160回もサイクルを回せます。 前者と後者とでどちらが生産性が高いかは比べるまでもないですよね。 これはものすごく単純化した例ですが基本的な考えは一般化できます。\nccacheとはなんですか？ ccache とはC/C++のコンパイル速度を高速化するツールです。 オープンソースであり、LinuxはもちろんWindowsでも動作します。 また、導入方法も簡単です。例えば、Androidのccacheを利用したビルドの効果測定が京都マイクロコンピュータ社のAndroidのビルドでccacheを使うに載っています。\nコンパイル速度にはHDD/SSDのアクセス速度やコンパイラライセンスの取得時間も関わるため一概には言えませんが、個人の経験では悪くても2倍は余裕で早くなるかともいます。環境との相性がよければ目を疑うほどの爆速になります。\nccache の仕組みは？ make の原理のおさらい ビルドを効率化するためのツールとして、一番基本的なツールは Makefileですよね。 もしmakeを使わなければ、ビルドするために毎回すべてのソースコードをコンパイルしなければなりません。 一方makeは、ソースコード（.c/.cpp、インクルードしている.h/.hpp）の最終修正時刻とそれから生成される.oファイルの生成時刻を比較して、 ソースコードの修正時刻の方が新しい場合のみソースコードをコンパイルします。 つまり修正したソースコードだけをコンパイルすることで全体のビルド時間を短縮します。\nccache の原理の概要 ccache はそこからさらに高速化をすすめます。 ソースコードをコンパイルするとき、コンパイラはまずマクロの展開などのプリプロセッサ処理を行います。 次に、そのプリプロセス済みのコードをコンパイルしてオブジェクトファイル（.o）に変換します。\nccacheは、その「プリプロセス済みのコード」と「コンパイルずみのオブジェクトファイル（.o）」の2種類のファイルをキャッシングします。 ここでいうキャッシングとはCPUのキャッシュメモリとは関係ありません。広義のキャッシュのことです。 具体的にいうと、ビルド時に生成したそれら中間ファイルをPCのHDD/SSDに保存します。 そして次回以降、その保存した中間ファイルが使えそうだったらそれを利用します。 これにより実際にコンパイルする回数が減り飛躍的にビルド時間を短縮します。\nものすごく単純な例でいうと、make → make clean →　再度 make とした場合、1度目の make と2度目に make のビルド時間はほぼ同じになるはずです（I/Oバッファの分だけ2回目の方が早いかもですが）。 一方、ccacheを使っている場合は、1度目より2度目の方が何倍も早くなります。 1度目の make 時にキャッシングしたデータを流用してコピーするだけでコンパイルはしないのであっという間に終わります。 びっくりするくらい早くなります。\nどのようにしてccacheが再コンパイルが必要かどうか判断しているかは、ソースコードファイルのハッシュ値を使っているようです。 興味のある方はGitHub - ccacheのコードを見てみてください。コード量はそれほど多くないので、頑張れば読めるかなと思います。\nまた、コンパイラを実行する回数が減る副次的な効果として、ライセンスの消費量が減ります。 例えば armcc などの有償のコンパイラをフローティングライセンスで使用している場合、開発チームが一度に使えるライセンス数には上限があります。 例えばライセンス数の上限が50で、100人の開発者が同時にビルドを始めると、ライセンスが枯渇してしまいライセンスがあくまで待たされたり、最悪ビルドに失敗したりしてしまう可能性が高くなります。 しかしccacheを使えば、キャッシングしたファイルが流用できる場合はコンパイラを実行せずに単にそのファイルをコピーするだけなのでライセンスを使用しません。よって使用するライセンス数を抑えることができます。\nccacheのインストール Linuxの場合はパッケージマネージャでサクッとインストールできるかと思います。もしできなければソースコードからビルドすればOKです。\nLinux でのインストール 大抵のディストリビューションにて、パッケージマネージャからインストールできると思います。下記のような感じでしょうかね。お使いの環境に合わせてパッケージマネージャでインストールしてください。\n1 sudo apt-get install ccache 1 sudo pacman -S ccache Mac OS X でのインストール homebrew でのインストールが一番楽でしょう。homebrewを導入した上で、下記のように実行するだけです。\n1 brew install ccache MSYS2＠Windows でのインストール WindowsでかつMSYS2（やGit for Windows）をお使いの方もパッケージマネージャからインストールできます。\n1 pacman -S ccache パッケージマネージャが使えない場合＠Linux 仕方ないので自分でソースコードからインストールしましょう。と言っても簡単ですが。下記のようにすればOKです。最初にソースコードを落としてくるところは、バージョンによってファイル名が違うので、そのときの最新版を持ってきてください。\n1 2 3 4 5 6 wget https://www.samba.org/ftp/ccache/ccache-3.4.2.tar.gz tar zxvf ccache-3.4.2.tar.gz cd ccache-3.4.2/ ./configure make make install ccacheを使う ccacheが動作するようにしましょう。gccなどのコンパイラコマンドの前にccaheを追加するだけです。つまり、たとえば\n1 gcc hoge.c -c -o hoge.o としてコンパイルしていたなら\n1 ccache gcc hoge.c -c -o hoge.o とするだけです。 ccacheが動作しているか確認するには、キャッシュのヒット情報をみてみればわかります。-sオプションでこれまでのキャッシュヒット率などの統計情報が表示されます。一度目はcache miss が増えると思いますが、2度目以降はcache hitのところがどんどん増えていくはずです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 $ ccache -s cache directory /Users/username/.ccache primary config /Users/username/.ccache/ccache.conf secondary config (readonly) /usr/local/Cellar/ccache/3.4.2/etc/ccache.conf stats zero time Sat Apr 14 00:50:12 2018 cache hit (direct) 32 cache hit (preprocessed) 0 cache miss 16 cache hit rate 66.67 % cleanups performed 0 files in cache 51 cache size 274.4 kB max cache size 5.0 GB ccacheを使うためのMakefileの変更例 Makefile を使っている場合は、下記のようなパターンルールがどこかに記載されているはずです。\n1 2 %.o : %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o これを下記のようにしてあげればOKですね。.cpp でも要領は同じです。\n1 2 %.o : %.c ccache $(CC) $(CFLAGS) -c $\u0026lt; -o $*.o これじゃちょっとわかりづらいかもしれないので、Makefileの具体例を下記のところに置いています。 ccache が使えればccache を有効に、cchacheがインストールされていなければ普通にgccを使うようにしています。\nset_toolchain.mk define_pattern_rule.mk まとめ 今回はC/C++のコンパイルを高速化するツールccacheについてご紹介しました。Windows、Linux、Mac OS Xそれぞれでのインストール方法と、Makefileの修正方法を説明しました。これでビルド時間が数倍になります！ ccacheのオプションの詳細はccache公式ドキュメントをご参照ください。\n","permalink":"https://nagayasu-shinya.github.io/posts/build-cache-compilation-ccache/","summary":"\u003cp\u003e最近はマイコンも多機能になってきて、ビルド時間もバカにならなくなってきています。\nそこで今回はC/C++のコンパイルを爆速にするccacheというツールをご紹介します。\u003c/p\u003e","title":"C/C++のコンパイルを高速化する｜ccache"},{"content":"おすすめの書籍を紹介します。ぜひ目を通してみてください。\nみなさん、技術書読んでいますか？ 最近はGoogle検索でだいたいのことはわかるようになってきましたが、やはりストックの知識（体系的な知識）は書籍のほうが便利だと思います。 そこでこの記事では、私が読んだことのある本の中でプログラマ、ITエンジニアにオススメの書籍を紹介してみたいと思います。新人さんや初心者から中級者向けの本をメインに取り上げて行きます。\n面白そうな本があれば、実際の書店でてにとってパラパラと内容を確認してみてくださいませ。お近くに書店がない場合は、出版社やAmazonの書籍紹介欄の目次だけでも眺めてみてくださいませ。なんとなく本の内容がわかるかなと思います。\nまた、わかる範囲で各本の紹介の末尾に「著者情報はこちら」としてTwitterアカウントおよびサイトも記載しています。こちらもあわせてご参照くださいませ。\nC言語 C言語 ポインタ完全制覇 中級者向けの本です。この本を読めば下記のような複雑なポインタの宣言もさらっと読めるようになります。\n1 int atexit(void (*func)(void)); また、文章がブログのような柔らかい語り口調なので読みやすいです。 たとえば p[i] が *(p + i) のシンタックスシュガーであるという説明のところでは下記のようにポイントが示されています。\n1 2 3 4 5 p[i] は i[p] とも書くことができる 上記のポイントに関するもっと大事なポイント でも書くな ポインタの話だけでなく、スタックやヒープなどの解説もあり、C言語全体の理解にとても役立ちます。さらに、普通の書籍ではあまり触れられることのない、現場で使われるC言語の定石も書かれていて、現場の空気を垣間見ることができます。 「ヘッダファイルには多重インクルードガードを」は当然として「ヘッダファイルはパブリックなものとプライベートなものにわけろ」などある程度の規模の開発では必須の ことを教えてくれます。 また、「アサーション assert を有効につかえ」のような基本的なことや「０と\\０とNULLのちがい」といった超マニアックな話題もあります。特にNULL周りの話は、わかっているつもりでもわかっていないことを思い知らされます。 また、下記のように書いたコードがどのようにふるまうかなんてこともわかります。マニアックですね。\n1 (**********printf)(\u0026#34;hello, world\\n\u0026#34;); // どうせ * は何もしない ポインタがなんとなくしかわかっていない人、C言語中級を目指す人にはお勧めの本です。現場の息遣いが感じられる良著です！\nリンク 著者情報はこちら\n@kmaebashi K.Maebashi\u0026rsquo;s home page C言語改訂版 2 はじめて学ぶCの仕組み C言語には列挙型 enumがあります。整数マクロの代わりに使われている場合が多いですが、enumの真価はそこではありません。 enumの理想（と哀しい現実）をここまでわかりやすく説明した本はほかに見たことがありません。\nenumをただの連番を作ってくれる型だとおもっているかたにぜひぜひ読んでほしい本です。目からうろこ間違いなしです。 enumのためだけに買っても損はないと思います。\nリンク エキスパートCプログラミング―知られざるCの深層 残念ながらいま（2022年03月時点）は絶版なのですが、もし本屋で見かけたら即買いです。 読んでいて面白いしC言語の深いところを知ることができます。インターポジショニングなんてこの本くらいしか説明ないのではないでしょうか。 リンカを使って既存の関数をおきかえる方法ですが、これを知っているとリンカのくせのある挙動が理解できます。 その他にもいっぱい面白い項目があって、なんでこれが絶版なのか、ほんとうに惜しい。C言語の本で間違いなくダントツでナンバーワンです。\nリンク C言語デバッグ完全解説 書籍名の通り、C言語に特化したデバッグの解説本です。バグを難易度で「初級」「中級」「上級」に分けて、それぞれのレベルでのよくあるバグを例示しています。 そしてそのバグの原因と修正方法を解説しています。デバッグとバグの起きにくいコーディングについて書かれた良書です。デバッグで困っている、コードレビューでよく指摘される、そのような方にオススメの本です。 初級について例を挙げると、下記のようなあるあるバグが例示されています。\n1 2 3 4 5 #define FREE(p) free(p); \\ (p) = NULL if (flag) FREE(p); freeした後にNULLを入れて安全にする、ということがしたかったコードですね。 ですがこれは下記のようにプリプロセッサで展開されます。いわゆるぶら下がり文のバグを思っ切り踏んでいます。\n1 2 3 if (flag) free(p); (p) = NULL; 解決方法はベテランの方はすぐに思いつくと思いますが、下記の例が挙げられていました。マクロ関数は do-while(0)で囲め、という古の戒め通りですね。\n1 2 3 4 5 6 7 #define FREE(p) do { \\ free(p); \\ (p) = NULL \\ } while(0) if (flag) FREE(p); 他にも中級、上級になると、バッファーオーバーランや乱数の精度、割り込み（シグナル処理）でのバグを解説しています。 複雑なのでここでは例示できませんが、書籍を手に取ってみて確認してみてください。\n後半はデバッグの方法（パラメータの振り方など）やバグの出にくいコーディングの方法を解説しています。気をてらったような記述はなく、現場でも口を酸っぱくして言われるだろう至極真っ当なことが書かれています。 ひとまずC言語の文法は覚えてコードはかけるけどデバッグに時間が取られている。コードレビューでバグの可能性をよく指摘される。そういう初級者から中級者の方にオススメの一冊です！\nリンク C言語 入門書の次に読む本 題名の通り、初心者が次のステップに進むための本です。 入門書にありがちがなリファレンス的な内容ではなく、どちらかというとプラクティスを説明している本です。 ヘッダファイルには何をかけばいいのか、ライブラリはどうするのか、などなど。入門書を一冊読み終えたひとにおすすめしたい本です。\nリンク プログラミング言語C 説明、いりますかね？いらないですよね。みんなご存知C言語のバイブル。 少なくともANSI Cの範囲ではもし何かあっても「K\u0026amp;Rの本に書いてある！」といえば相手を黙らせられます。\nただ難易度は少し高いです。Unixを知っていること前提な感じなので全くの初心者には向きません。情報系の大学生にちょうどいいかな、という感じです。 C言語をやるならとりあえず持っておくべき本でしょう。\nリンク 組込み開発者におくるMISRA‐C:2004―C言語利用の高信頼化ガイド 自動車業界のひとたちが守っているコーディングルール MISRAの説明の本です。 自動車はうっかりバグっちゃいましたテヘペロではすまないのでけっこうルールが厳しいです。 他の業界がそこまでやる必要があるかというと微妙ですが、部分的に取り入れるのはありだと思います。 意地でもバグを出したくないぜ！そのためなら自由を捨てるぜ！という方はぜひ。\nリンク CERT Cセキュアコーディングスタンダード こちらはセキュリティ関係のひとが守るコーディングルールですね。うっかり脆弱性を作り込まないための本です。ほほう、そんなところに脆弱性が……？となるような項目がたくさんです。\nリンク CプログラミングFAQ Cプログラミングのよく尋ねられる質問 ちょっと古いのですがこれも名著です。C初心者がつまづくところをFAQ形式で説明しています。 多次元配列のポインタなんかぜったいつまづくよね、とおもったり。 対象にしているCのバージョンが古いのでたまに今の規格とあっていないところもありますが、けっこうそのまま使えます。\nリンク プログラミング診断室 これも名著ですね。やばいコードが盛りだくさんです。 世の中って広いんだなぁと思わせてくれます。\nリンク ハッカーのたのしみ 書籍名だけみると、ネットワークの脆弱性の本かと思ってしまいますが、実際の内容は異なります。 たとえばもっとも簡単な例だと、１Word中の1のBitを数えるような、ビット演算レベルのアルゴリズムを紹介している本です。\nこういうと「コンパイラが最適化してくれる」という意見もあるかもしれませんが、アルゴリズムレベルで異なるものは最近のコンパイラと家でもなかなか勝てません。たとえば最初に例をあげた「１Word中の1のBitを数える」というコードですが、本書では下記のようなコードを挙げています。配列も使わないし繰り返しどころか条件分岐すらない、ビット演算と加減算のみの高速なコードです。 なぜこれでビットの数え上げができるのか、本書では数学的な丁寧な解説があります。理論好きなかたにはたまらない一冊でしょう。\n1 2 3 4 5 6 7 8 9 int pop(unsigned int x) { x = x - ((x \u0026gt;\u0026gt; 1) \u0026amp; 0x55555555U); x = (x \u0026amp; 0x33333333U) + ((x \u0026gt;\u0026gt; 2) \u0026amp; 0x33333333U); x = (x + (x \u0026gt;\u0026gt; 4)) \u0026amp; 0x0F0F0F0FU; x = x + (x \u0026gt;\u0026gt; 8); x = x + (x \u0026gt;\u0026gt; 16); return x \u0026amp; 0x0000003FU; } このような簡単な例からはじまり、ビット並び替え、整数の乗算除算、平方根や行列反転、ヒルベルト曲線など高度な話もでてきます。下記の記事もこの書籍を参考にしています。 C言語で2の累乗（2^n）への切り上げ＆切り捨て\n組込みシステムがリッチになってきたとはいえ、ブートローダのようにまだまだ1Byte単位で戦わざるを得ない場面もあります。 カーネルを触る人なら、ディスパッチャを1命令でも少なくしたいという要求もあると思います。 そのような限界へ挑戦するプログラマにうってつけの名著です。\nリンク RTOS, 組込みシステム リアルタイム組込みOS基礎講座 基礎講座の題名に反してちょっと内容がむずかしいですが、これをよめばRTOSのことをひととり解ると思います。セマフォやメッセージキュー、同期やデッドロックなど避けて通れない話題がたくさんです。ひとまず読んでほしい本。\nリンク 組み込みソフトウェアの設計\u0026amp;検証 タスク設計の勘所なんかを学べる本です。RTOSだと設計といえばタスクスケジューリングの設計が主ですが、その方法を解説しています。 破綻しない方法、デッドロック市内方法など。説明がわかりやすいのでおすすめです。後半はモデルを使った数学的な話がでてきて難易度が上がります。\nリンク μITRON準拠TOPPERSの実践活用 TOPPERS/JSPの本です。網羅的な内容ではないですが、いろんな各アーキテクチャへのポーティングの話があってカーネル理解の勉強になりますね。\nリンク CとGNU開発ツールによる組み込みシステムプログラミング 隠れた名著だと思います。もっと売れていていいと思うんですけどねぇ……。 コンパイルやリンク、ロードなどの説明から始まってDMAやLEDなどを制御するRTOSのデバドラの作り方、最後にRTOSの説明をしています。普通の教科書では概念だけで済ませるところをちゃんと説明してくれるのでホント助かりました。おすすめです。\nリンク 組込みI/Oインタフェース基礎講座 組み込み関係の本ってさも当然のようにSPIやらUARTやらI2Cの話が出てきますが、それらを説明した本ってなかなかないんですよね。これはそういうI/Oを説明した本です。かなり珍しい本なので、そこらへんの話が苦手なひとはぜひ読んでおくといいと思います。\nリンク 30日でできる! OS自作入門 おそらくこの本が OS自作本のはしりじゃないかと思います。 組み込みというより普通のPCのハードで動かす本です。ただ内容は組み込みにも応用できる話題がたくさんです。RTOS というより汎用OSのカーネルとかに興味があるひとが向いている気がします。\nリンク ARM, Cortex, プロセッサ CPUの創りかた 言わずとしれた名著。これを超える本は出てこないのでは。CPUの作り方をまなびながらハードの基本が学べます。プルダウン？なにそれ？というレベルでも読めます。とにかくまず読んで。これをよまなきゃハードは始まらないぜ。\nリンク ARM組み込みソフトウェア入門 Cortexより前の、クラシックARMのときの本。ちょっと古いんですが、ARM系の組み込みソフト屋としては知っていて損はないことばかり。\nリンク 開発プロセス, マネジメント アジャイルサムライ アジャイルの入門書といえばアジャイルサムライ！といえるくらい有名ですね。 マスターセンセイが、軽妙な語り口でわかりやすくも厳しくアジャイルについて教えてくれます。\n絵などが豊富でとても読みやすいです。そして内容も濃いです。アジャイルの根本的な考え方からはじまり、アジャイル的なチーム作り、見積もりのやり方、プロジェクトの進め方、そしてプログラミングの仕方まで説明があります。 出てくる用語をざっと挙げると「エレベータピッチ」「インセプションデッキ」「イテレーション（スプリント）」「スタンドアップミーティング」「ベロシティ」「ふりかえり」「WIP」など、アジャイルに欠かせないものをきっちりおさえてあります。\n他の本だと難しく書かれている説明も、現場にそった説明がされていて、とても理解しやすいですね。まずはこの本から始めるのがいいと思います。チケット駆動開発をするにもこれを読んでおくと導入しやすそうです。 ただ、唐突に「ファーンファーンウィーヒッダステーッステー」とか書かれていたのは笑ってしまいました。楽しくアジャイルを学べる本です。\nリンク 人月の神話 古典的名著。人を増やせば早く終わるってもんじゃねーぞというのを指摘した本。読んでないと話にならないくらいの名著です。必読。\nリンク Redmineによるタスクマネジメント実践技法 おそらくチケット駆動開発 TiDDの最初の本ではないでしょうか。いまでこそ当たり前になっているチケットによる開発ですが当時はまだ浸透していませんでした。おすすめプラクティスものっていて、これも必読。\nリンク Linux, Unix, シェルスクリプト UNIXという考え方 Unix/Linuxを使うならこれはよんでおかないと話にならないですね。Unixがどういうポリシーで作られているかを述べた本です。 1つのコマンドには1つのことをやらせる、データはテキストであつかう（だからパイプなどでどんどんコマンドをつないでいける）など、基本をぎゅっと抑えられます。\nリンク 動くメカニズムを図解\u0026amp;実験! Linux超入門 隠れた名著です。題名からはわかりづらいですが、組み込みLinux向けだと思います。対象読者はRTOSなどで組み込みシステムの基本を抑えた人向けかなと思います。RTOSからの移行組にぜひおすすめしたい。\nリンク 入門UNIXシェルプログラミング シェルプログラミングといえばまずはこの本！という名著。シェルとはなにかから始まり段階を追シェルってシェルスクリプトに向かいます。 途中には避けては通れないsedなどの使用法も解説もあります。後半には豊富なサンプルがあり学習しやすいです。\nbashの拡張機能などは載っていませんが、この本の書き方ならどこの環境でもまず動くと思うので、何はともあれこの本を読んでから拡張機能にi手を出すのがいいと思います。\nリンク 私はどのようにしてLinuxカーネルを学んだか Device Tree編 おそらく唯一のDevice Tree専門の本です。 最近の組込み業界はARM一色ですが、組込みLinuxも例外ではありません。そしてARM（だけに限りませんが）をLinuxで動かすためにはDevice Treeの知識がかかせません。 結構最近できた、ハードの差異を吸収する仕組みなんでが、こいつがなかなかに難しい……。そして情報もすくない。そんな八方塞がりの状態をなんとかしてくれる良書です！\nリンク Git 独習 Git ソフトエンジニア向けのGitの解説本です。これ一冊あればひとまずOKでしょう。 対象としては「いつもなんとなくpushとかpullとかしてるけどなんなのかはよくわからん」「環境がLinuxなのでSourceTreeとかの素敵なGUIツールが使えない」「コマンドラインでやらざるを得ない」というような、 ちゃんとGitを真面目に理解したい、理解しないといけないエンジニア向けの本です。\n最近は非エンジニア向けに書かれた解説書や、GUIツール前提の本なども多く、それはそれでわかりやすいです。 確かにルーチンな作業はそれで十分なのですが、大規模開発でブランチを多用したり、開発リーダとしてGitの運用ルールを考えたりするような場合は少し心もとないです。 「rebaseって何？」とか言ってるようだと、あとあと詰んでしまいます。 この本は最初は易しいところから、少しづつコマンドを学んでいく形になっています。 最終的にはブランチを生やしたり、それを分岐元に追随されたり、マージしたりということを自在にできるようになります。\n400ページ超あり、なかなかの分量ですが、その分ていねいに書かれています。 Gitの入門書を読んだけどいまいち何をしているかわからない人、コマンドラインでGitを操作したい人にはうってつけの本です！！\nリンク 実用 Git オライリーのGit本です。オライリーだけあってけっこう高度です。 Git初心者がいきなり読むのはおすすめできません、先に独習Gitを読んでからこの本に進むことをおすすめします。\nたとえばGitの得意ないい感じにマージするってのはこんなにむずかしいことやっているのか、と感心しました。\nリンク 技術系その他 Docker＆Kubernetesのきほんのきほん これはわかりやすい。Docker 最初の一冊におすすめです。Docker をこれから始める人向け。フルカラーで図もたくさんでとても親切。これ読んでわからなかったら、正直もう無理だと思う。それくらいわかりやすいです。\nリンク 暗号技術入門 数学ガールで有名な結城先生による暗号の解説書です。 最近は IoTの広まりにより組込み機器もネットにつながる時代です。そのため組込みエンジニアも、暗号処理や公開鍵基盤などのセキュア技術も知っておく必要が出てきています。 しかし専門書はアルゴリズムがムスカしい数式で説明されており、その道の人でなければ理解するのが難しいです。\nいっぽうこの本では、暗号の処理をおもにデータフローのような図解で説明してあり、また、実際のどのように使われるのか、なぜその暗号が必要なのかをアリスとボブのようなキャラクターで例示してくれるのでとてもわかりやすいです。\nさらに、専門家なら常識すぎてあまり言及されないようなこともちゃんと教えてくれます。 例えば「どんな暗号もいつかは解読される」「この製品は絶対に解読できない暗号をつかっている、などの宣伝文句は疑ってかかろう」という旨の注意喚起もあります。\n内容としては、暗号の歴史的背景（シーザー暗号やエニグマなど）から始まり、対象暗号（DES、AESなど）、公開鍵暗号（RSAなど）について解説されています。 さらにハッシュ（SHAやKeccaｋなど）やメッセージ認証（MAC)、デジタル署名、さらに電子証明書、公開鍵基板（PKI)の解説と続きます。さらに鍵とはなにか、乱数とは、などすこし高度な内容がつづき、 最後に「暗号技術を組み合わせる職人芸」であるPGPとそのGNU実装のGPG（Gnu Privacy Guard)の解説があります。\n補足として、仮想通貨やビットコイン、また、最近の暗号のトレンドである楕円曲線暗号についても少しですが触れられています。 いきなり暗号の専門書をよんでも挫折することうけあいなので、一歩一歩わかりやすく解説されているこの本でまずは基本を押さえるのがよいかと思います！\nリンク 著者情報はこちら\n@hyuki 結城浩 暗号と認証のしくみと理論がこれ1冊でしっかりわかる教科書 暗号を解説した本です。図や例がおおくわかりやすいです。また新しい本なので最近の暗号についての説明や技術について説明があるのも嬉しいです。内容もしっかりしています。\n序盤は初心者向け、中盤は高校〜大学学部くらいのレベルの話があります。後半はビジネスロジックに近いところのお話。充実した内容でかなりおすすめです。\nリンク ITエンジニアとして生き残るための指南書。 自分を守りアップデートするための18のテクニック 技術書や研修などで学ぶような知識でなく、現場でしかも休憩時間なんか同僚や先輩との会話で出てくるような話題が多い稀有な書籍ですね。 ソフトウェア開発のことももちろん書いてありますが、それよりもふと現場で交わされる話題が多いです。そういうのってなかなか文書で読むことはない、現場で伝承されるある種の口伝です。 例えば「休日出勤の方が邪魔入らないよね」てのはよく聞くことがですが「代休取ればいいしね！お賃金ももらえるし！」まで書いてある本は見たことがない。職場ではよく聞く話題ですが。あとは「タバコ休憩」「トイレでの居眠り」なんかも現場ではよく出る話題ですね。 あとは「バグを市場に出してしまったとき、果たしてバグを入れてしまった開発者個人に責を求めるのは正しいのか？」というような話題もあります。 あまり書くとネタバレになってしまうのでここら辺にしておきますが、読者によって下記のような反応になるでしょう。 ・若手（5年未満くらい） →　ほえー。まじかそうなのか！ ・中堅（20年未満くらい）→　あるある笑 ・ベテラン（20年以上）→爆笑（著者談） ゴリゴリの技術書といよりはエッセイに近い雰囲気でとても読みやすいです。電車内とかでも読めるのでおすすめです。 ITエンジニアとして生き残るための指南書\nリンク ターミナルソフトTera Termガイドブック みんなご存知Tera Termのガイドブックです。 前半はTera Termの使い方、後半はTera Termの開発、メンテについてです。\n前半のTeraTermの使い方は、メンテナのかたが書いてあるだけあって細かい機能なども書いてあります。 透過ウィンドウ設定ができるとか、10年以上使っている私もしりませんでした。\n他にもマクロやショートカットなどの説明があります。 いつも通り使う分には困ってなくても、より便利に使うために役立ちそうな情報がたくさんあります。 前半のTera Termの機能の使い方もいいのですが、個人的におすすめなのは後半のTera Termの開発についてです。\nOSSとしてTera Termのメンテが行われていった経緯などがつぶさに書いてあります。 Tera Term をアップデートすべく、オリジナルの作者である寺西氏に著者がコンタクト取ろうとする様子などが、実体験として書かれています。\n世の中にはたくさんの素敵なOSSのソフトがあり、変更履歴やイシュー管理などされていますが、メンテナの心情や動機までは記録されていません。 この本は、そのようないわゆる「中の人」の心情が書かれています。これから先、OSSに関わってみたいという人にぜひともおすすめです！！\nちなみにですが、不肖私この本の帯を書かせてもらいました。でも大丈夫です、何部売れてもわたしは一銭もはいりませんのでそこは安心してお買い求めください！！\nリンク 簿記, 財務 会社は利潤追求を旨とする組織である以上、会社員はお金や資産について最低限は知っておかなければなりません。 そのお金について学ぶ方法の一つとして「簿記」を勉強することが挙げられます。 特に日商簿記検定は公的資格とみなされ、本屋に行けば大量の参考書がありますし、さらに履歴書にもかけてお得です。 また、IT系の資格試験に比べ受験料も大変リーズナブルでお財布に優しい。\n簿記を少しだけでもかじっておくと、世の中のお金の話が全く異なって見えてきます。 あまり技術を知らない他業種の方がIT製品やサービスに触れるのと、私たちエンジニアがそれらに触れるのとでは見えるものが違うのと同様に、 簿記を知らない人が見る社会のお金に関することと簿記を知っている人が見る社会のお金に関することは見え方が全く異なります。\nわかりやすい例で言えば「借金（負債）」ですね。簿記を知らない人は「負債（借金）→悪いこと！」と短絡してしまいますが、 ちょっとでも簿記をかじっていれば「負債（借金）→現金が増える→それを投資して機材買ったりしてより利益を出せる（かも）」と考えることができるわけです。 お小遣い帳の発想から抜けられるんですね。\nゲーテだか昔の偉い人が「複式簿記は人類の偉大な発明の一つ」という旨の発言をしたといわれていますが、確かにその通りかもしれません。 お小遣い帳から複式簿記への進歩は、運動方程式や微積分の発見に匹敵する、というと大げさかもしれませんが、オブジェクト指向のパラダイムシフトより大きな変化だったのかもしれません。\nまた、よく転職市場では「ポータブルなスキルを持て」と言われます。つまり社外でも通用するスキルを持っていると転職で有利だよ、ということです。 例えば特定のプログラミング言語は他社に行くと使えないかもしれません。 まあプログラミング言語は比較的どこの現場でも使えますが、特定の開発ツールだと使えない危険性はもっと高まります。\nエンジニアの技術は可搬性がない場合があるんですね。比較して簿記などのお金のスキルはどの会社でも必須です。 業界も関係ありません。貸借対照表B/Sや損益計算書P/Lのない会社はないでしょう。どこでも使える簿記。多分50年後も使える簿記。すごい。\nということで、エンジニアなわれわれも簿記の初歩くらいは知っておかないといけないので、そのための良書をご紹介します。\nとある会社の経理さんが教える楽しくわかる！簿記入門 パンダさんたちが、軽妙なボケツッコミをしながら簿記の基本を教えてくれる本です。 漫画と文章の２種類の解説で、簿記の本とは思えないくらいスラスラと読めちゃいます。\nときどき唐突にマッチョになって簿記の重要性を説くパンダさんとかいい味出しています。 もちろん日商簿記3級に役立ちますが、試験対策というよりも、簿記の本質基本を現場の人が丁寧に教えてくれる本だと思います。\nリンク 著者情報はこちら\n@soltaril とある会社の経理さん とある会社の経理さんが教える楽しくわかる！原価計算入門 原価計算は日商簿記2級の範囲（工業簿記）ですので、これから簿記を始める人向けでなく簿記3級を取得したくらいんレベルの人向けの本です。 これまたパンダさんたちが、軽妙なボケツッコミをしつつ難しいはずの工業簿記の原価計算を教えてくれます。\n今回も漫画と文章の２種類の解説で、簿記の本とは思えないくらいスラスラと読めちゃいます。 パンダさんに加え、友人からカネをちょろまかしようとするサルさんとかいい味出しています。\nもちろん日商簿記2級に役立ちますが、試験対策というよりも、これも簿記の本質基本を現場の人が丁寧に教えてくれる本だと思います。 マンガで原価簿記なんて説明できるのか？といぶかしがる方もいらっしゃるかもしれませんが、大丈夫です。 やはり現場の人の書いた本は本質を抑えています。いきなり簿記2級の工業簿記をやるのではなく、先のこの本を読んでからの方がスムーズに進められると思います！\nリンク パブロフ流でみんな合格 日商簿記3級 テキスト\u0026amp;問題集 簿記検定界の愛されキャラ、パブロフくんの簿記3級編です。 4コマ漫画と文書での説明とでわかりやすく解説してくれます。このパブロフくんが意外とシュールで、持っている株（売買目的有価証券）が上がるようお祈りしたり、株価が下がれば株券を破っちゃったり、従業員に給与を払うのを嫌がったり、可愛さ大爆発です。 パブロフくんとなら頑張れる気がします！\n下記では、この記事を書いている時点での最新版へのリンクを貼っていますが、数年に一度改訂版が出されるのでねんために改訂されてないか確認してくださいね。\nリンク 著者情報はこちら\n@atsuko_pop @pubboki パブロフくんが日商簿記２級、３級を目指すブログ ビジネス, 自己啓発系 職場の問題地図 職場の「あるある！」な問題を取り上げ、その対策案を示している本です。 「無駄な会議」「作業の属人化」「報連相の不備」「仕事しない人がいる」など、どこの職場でもありがちな問題を大きく11つ取り上げてあります。\nこの本の特徴は、ベテランなら「経験則」わかっているこれらの問題の対策を、「場」と「プロセス」に焦点を当て言語化してシステマチックに説明してあることです。 例えばわかりやすい例として無駄会議をあげます。私の方で要約すると「目的の明確化」「出席者の厳選」「議事録容易化」「決定事項、宿題事項、次回予告の3点確認」の5つの対策が挙げられていました。 それらの対策と得られる効果らを星取り表にして説明してあります。\n単に対策をつらつら場当たり的に書いているのでなく、ちゃんと体系的にまとめられているのでとてもわかりやすいです。 また、各個人向けの仕事術的なことも書いてあります。基本的なことを抜粋すると「仕事とはインプットを成果物に変換すること」と定義し、 「インプット」「アウトプット」「目的」「関係者」「効率」の5つの要素に分解しています。いわゆる仕事がデキる人はこんなの当たり前だと思うかもしれませんが、 案外これを意識していない人は多いものです。特にこれから経験を積んでいこうとする若手は、これらに気づくまでにそれなりの時間を要する可能性があります。\nこれを体系的に言語化して理解できるのはメリットが大きいと感じます。 また、これら5つの要素をフレームワークとして、それぞれの職場の問題に当てはめ解決策を提示していきますので、解決のフローが明確となっています。 とてもわかりやすく書籍の構成、まとめかた自体が参考になります。 職場をマネジメントするマネージャ層だけでなく、これから仕事を覚えていく若手にもオススメの名著です！\nリンク 著者情報はこちら\n@amane_sawatari あまねキャリア工房 武器がないエンジニアは肯定を続けることで、武器を手にする インフラ勉強会の立ち上げ人の佐々木康介さんの処女作です。 「技術的な強みがないエンジニアがどうすれば戦っていけるか」を佐々木さんの視点で書いた本です。その内容は、一貫して「肯定しよう」というメッセージです。\n一般的に、技術書の著者というのは難関大学出身だったり有名企業の研究開発部門の人だったりということが多いですが、佐々木さんは「大学文系→商社営業→インフラエンジニア」という経歴の持ち主です。 理系バカ（私含め）が多いIT業界において、独特な経歴からの視点でIT業界を観察し生き抜いていく心得がたくさん書かれています。\nイケてるプログラミング言語や流行りの分野の話などは出てきません。着実に、日々の業務を成し遂げ成長していくか、その視点で実体験をもとに書かれています。題名にもなっている「肯定」の力で物事を捉え、やるべきことやれるべき事を実行していこうというスタンスですね。 何かと後ろ向きに物事を捉えがちな我々理系エンジニアとしては、新しい視点を教えてくれる良書です。もちろん得意不得意があるので、そのまま真似はできないかもしれませんが、自分の今の強みとミックスさせていけば必ずや前に進めると思います。 「20分で読めるシリーズ」とのことで分量は多くないので、通勤時間などでサクッと読めると思います。自分は後ろ向きだなあ、実行力がないなぁ、などと悩んでいるエンジニアに、ぜひ読んでもらいたい本です。\nリンク 残酷すぎる成功法則 成功するためのハウツー本は巷にあふれていますが、どれもだいたい作者の体験談とかで「それってアナタの主観ですよね？」といいたくなるようなものばかりです。しかしこの本は、あらゆる法則にエビデンス付きで考察しています。つまり科学的なのです。すべてに論文などのエビデンスをもとに書いてあります。 よくある成功者の自慢話ではなく、真に客観的な成功法則を知りたいかたにぜひおすすめしたい本です！\nリンク ドキュメント作成 エンジニアのためのWord再入門講座 「くたばれ！Excel方眼紙！」という章があったりして過激な感じをうけますが、内容はとても真摯な本です。 MS Wordの「スタイル」という機能をつかって、見栄えよくかつメンテナンス容易にできるようにしてくれる本です。\n筆者の「ドキュメントの内容は当たり前品質」という考え、つまりプロなら内容はちゃんとしていて当たり前という考えが随所にでています。 内容がちゃんとしているのは当たり前という考えのもと「１に見栄え、２にメンテナンス性」という最初の段階と断言しています。\nこう書くとなんか見栄え重視の薄っぺらい本かと思うかもしれませんが、さにあらず。まるでソースコードを書くように「設計」や「DRY原則」を重視しています。 むしろ、見栄えに時間をとられたくない硬派なITエンジニアのための本といえます。 そのためのMS Word のほんとうの実力を引き出してくれる本です。\nリンク 伝わるデザインの基本 題名からしてデザイナーさん向けの本に見えますが、そうではありません。 むしろ非デザイナー向けの本です。もともとが「研究発表のユニバーサルデザイン」というサイトがベースになっており、オシャレな広告を作るというようなものではありません。 わかりやすい表やグラフ、図を作るためのものです。それらのコツを伝授してくれます。\n文字を詰め込みすぎるなとかフォントの選び方などの超ベーシックなところから、グラフのみやすい作り方、見やすい表の枠組みの作り方、さらに配色や余白、ベクター形式がいいかビットマップがいいかなどの細かいところまで網羅しています。 これさえ読んでおけば、普通にエンジニアが資料を作るには十分すぎると思います。\nリンク 著者情報はこちら\n伝わるデザイン\n考える技術・書く技術―問題解決力を伸ばすピラミッド原則 古典的名著といえる本です。よくある「結論から書け」などという曖昧模糊とした方法論ではなく、もっと具体的な方法を教えてくれます。 その原則さえ抑えておけば、メールでもドキュメントでも、文章を書くのが随分と楽になります。仕事で文章を書くのに詰まったときはいつもこれを引っ張り出しています。\nただ惜しむらくは、文化的背景の違いなのか、なぜか本書はわかりづらいということです。 例文が難しすぎる気がします。ただ、書いてある原則自体はシンプルなので、ちょっと辛抱して読んでみてみると良いかと思います！\nリンク 「分かりやすい表現」の技術 意図を正しく伝えるための16のルール こちらも古典的名著といえる本です。 どういうものがわかりづらいのかの実例をあげ、それが何故わかりづらいのかを解説し、改善版を示してくれます。 非常にわかりやすい本です。また新書サイズなのでいつでも読めるのも嬉しいところです。 「考える技術書く技術」を読む前にこちらを読んでおくといいかもしれません。これも必読の本です。\nリンク ","permalink":"https://nagayasu-shinya.github.io/posts/book-recommendations-engineering/","summary":"\u003cp\u003eおすすめの書籍を紹介します。ぜひ目を通してみてください。\u003c/p\u003e","title":"おすすめ書籍｜組込みエンジニア向け"},{"content":"Arduino IDE でビルドしたときにコンパイル遅い問題を解決する方法を紹介します。\nArduino IDE でビルドしたとき「コンパイル遅いなぁ」と思ったことはありませんか？ １行しかソースコードを修正していないのにフルビルドが始まってイライラすること、ありませんか？ ためしに手元のESP-WROOM-02にてテキトウなプロジェクトをビルドしてみたところ、2分30秒近くかかりました。 個人的には、ソースコード量から考えるとかなり遅いという印象です。 この記事ではこのビルド時間を短縮する方法をご紹介します！\nどうしてビルドに時間がかかっているの？ これは、Arduino IDE のデフォルトの挙動によるものです。 コンパイルしたファイル（オブジェクトファイル .o）の出力先ディレクトリが、IDE立ち上げたりターゲットを切り替えたりしたときに異なるディレクトリに設定するためです。 もう少し具体的にいうと、Arduino IDE はランダムな数字列を含んだディレクトリを作成し、その中にオブジェクトファイルを出力します。 このランダムな数字列がちょくちょく変更されるため、以前にコンパイルしたオブジェクトファイルを再利用できずに、再度フルビルドをすることになりビルドに時間がかかるわけです。\nちなみに、Windows では下記のディレクトリを利用します。「XXXXXX」がランダムな数字列になるところです。 C:\\Users\\username\\AppData\\Local\\Temp\\arduino_build_XXXXXX\\\n逆にいえば、オブジェクトファイルの出力先を毎回同じになるようにすれば、ソースコードを修正しない限りはリコンパイルしないので、ビルド時間が短縮できます！\nオブジェクトファイル出力先を確認する まず、現在の設定でどこにオブジェクトファイルが出力されるかを確認してみましょう。 確認するために、IDEのコンパイル結果出力部分にコンパイラのメッセージを出力するようにします。\nまずはIDEを起動し、メニューより「ファイル」→「環境設定」を選択します。\n次に、環境設定のウィンドウが開きますので、設定タブを選択し、「より詳細な情報を表示する」というところを探します。 そこに「コンパイル」と書かれたチェックボックスがあるので、これをチェックします。 IDEのバージョンや設定言語によって微妙に場所が異なるかもしれませんが、下記の図を参考にしていただければわかると思います。\nこれで、IDEでビルドしたときにどこにオブジェクトファイルを出力しているかがわかるようになります。 下記のようにコンパイルメッセージ出力までのコンパイラの実行コマンドが出力されます。 下の画像ではコマンドが長すぎて見切れてしまっていますが、赤枠のところにコンパイルコマンドが表示されています。 そのコマンドのオプションでオブジェクトファイルの出力先を指定していますので、そのオプション部分を見ればOKです。\nそこには、細かいところはターゲットによりますが、下記のようなコマンド列がずらずらと並んでいるはずです。 オブジェクトファイルの指定は -o オプションです。 下記の例でいうと一番最後の-o \u0026quot;C:\\Users\\\\AppData\\Local\\Temp\\arduino_build_925358\\core\\WInterrupts.c.o がそれです。 この arduino_build\\925358\\ がランダムに変わってしまう箇所です。\n\u0026quot;C:\\Programs\\arduino\\hardware\\tools\\avr/bin/avr-gcc\u0026quot; -c -g -Os -Wall -Wextra -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -``DF_CPU``=16000000L -DARDUINO=10805 -``DARDUINO_AVR_UNO`` -``DARDUINO_ARCH_AVR`` \u0026quot;-IC:\\Programs\\arduino\\hardware\\arduino\\avr\\cores\\arduino\u0026quot; \u0026quot;-IC:\\Programs\\arduino\\hardware\\arduino\\avr\\variants\\standard\u0026quot; \u0026quot;C:\\Programs\\arduino\\hardware\\arduino\\avr\\cores\\arduino\\WInterrupts.c\u0026quot; -o \u0026quot;C:\\Users\\\\AppData\\Local\\Temp\\arduino_build_925358\\core\\WInterrupts.c.o\u0026quot;\n一度IDEを終了させてからもう一度ビルドを実行すると、その数字列が変わるはずです。\nオブジェクトファイル出力先を固定する IDEを再起動したりターゲットを切り替えたりするたびにせっかくコンパイルしたオブジェクトファイルが無駄になるのを避けるため、オブジェクトファイルの出力先をランダムでなく固定します。 その方法は preferences.txt ファイルを編集します。 このファイルを開くために、まずはIDEを起動し、メニューより「ファイル」→「環境設定」を選択します。 すると下記のようなウィンドウが開きます。赤枠のところにpreferences.txtのパスが書いてあります。 ここをクリックするとそこのフォルダが開きます。\nこの preferences.txt を編集するのですが、このファイルを開くまえに必ずIDEを終了してください！ このファイルはIDE終了時に更新されますので、IDEを終了させずにファイルを編集しても、変更内容が破棄されてしまいます！\nIDEを終了させたらお好きなエディタでpreferences.txtを開いてください。 メモ帳でもなんでもOKです。ファイルはこんな感じのテキストファイルです。\nこのファイルにビルドパスを追記します。下記のような1行を追加して、build.pathを指定してください。 build.path=C:\\Users\\username\\AppData\\Local\\Temp\\arduino_build\nパスは任意で構いませんが、存在しないディレクトリを指定するとエラーが発生しますのでご注意ください。 特にこだわりがなければ、システムの TEMP ディレクトリの下にサブディレクトリを作成して、そこを指定すればよいでしょう。\nWindows の場合は上記の例のようにしておけばよいかと思います（username のところはご自身のユーザー名に置き換えてください） 上記の例では、下記のようにDOSでディレクトリを作成すれば良いでしょう。システムのTMPディレクトリに移動して、任意の名前のディレクトリを作成しています。\n1 2 C:\\Users\\username\u0026gt;cd %TMP% C:\\Users\\username\\AppData\\Local\\Temp\u0026gt;mkdir arduino_build これで、ランダムでなく毎回おなじディレクトリにオブジェクトファイルが生成されるようになります！\n設定変更後のオブジェクトファイル出力先を確認する これでオブジェクトファイルが同じ場所に生成されるようになります。 念のため、IDEを再度立ち上げて確認してみましょう。\nこれまで述べた設定例にした場合、コンパイルコマンドが下記のようになっているはずです。 -o \u0026quot;C:\\Users\\\\AppData\\Local\\Temp\\arduino_build\\core\\WInterrupts.c.o\u0026quot;となっています。 ランダムであった数字列がなくなっているのがわかると思います。\n\u0026quot;C:\\Programs\\arduino\\hardware\\tools\\avr/bin/avr-gcc\u0026quot; -c -g -Os -Wall -Wextra -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -``DF_CPU``=16000000L -DARDUINO=10805 -``DARDUINO_AVR_UNO`` -``DARDUINO_ARCH_AVR`` \u0026quot;-IC:\\Programs\\arduino\\hardware\\arduino\\avr\\cores\\arduino\u0026quot; \u0026quot;-IC:\\Programs\\arduino\\hardware\\arduino\\avr\\variants\\standard\u0026quot; \u0026quot;C:\\Programs\\arduino\\hardware\\arduino\\avr\\cores\\arduino\\WInterrupts.c\u0026quot; -o \u0026quot;C:\\Users\\\\AppData\\Local\\Temp\\arduino_build\\core\\WInterrupts.c.o\u0026quot;\n一度コンパイルすれば、ソースコードを修正しない限り再度コンパイルすることはなくなりました。 例えば一度IDEを終了してから再度立ち上げてビルドした場合、下記のようにほとんどコンパイル処理が走りません （「オブジェクトファイル出力先を確認する」のところで示したキャプチャと比較すれば処理の短さがわかるかとおもいます）。\nこれでソースを変更していないのにフルビルドが走って待たされることがなくなります！お疲れ様でした！\nまとめ ArduinoIDE　にてビルドが遅い原因とその回避方法を示しました。オブジェクトファイルの出力ディレクトリ名をランダムに生成しているため、IDEを再起動したりするとフルコンパイルになります。これを設定ファイルpreferences.txtの編集により回避できます。開発速度を加速したい方は試してみると良いかもですね！\n","permalink":"https://nagayasu-shinya.github.io/posts/arduino-build-optimization-path/","summary":"\u003cp\u003eArduino IDE でビルドしたときにコンパイル遅い問題を解決する方法を紹介します。\u003c/p\u003e","title":"Arduino IDEのビルドを速くする｜オブジェクトファイルの出力先を固定する"},{"content":"JenkinsとPMD CPDを使って、コピペコード（重複コード）を継続的に検出・監視する方法を説明します。\nコードの品質についてみなさんはどんなことを気をつけていますでしょうか？ カバレッジなんかがよくある指標ですね。他にも静的解析ツールの指摘数なんかもありますね。 他には「コピー＆ペーストで作られたコードがどのくらいあるか」というのも指標になりうると思います。 コピペでコードを書くのは基本的にやってはいけないことです。 ですので、そのようにして作られた重複コードが多いかどうかは一つのメトリクスになりうると考えます。\n「そんなの常識だぜ？」と思うかもしれませんが、この世は広いもので、この基本原則を守らない、むしろ積極的にコピペを推奨するプログマもいるのが実際です。 そのような不埒者にプロジェクトの足を引っ張られるのも癪に障るというもの。 そこでこの記事では、Jenkinsを使ってコピペで作ったコードをチェックして可視化し、さらにその量の推移を可視化する方法をご紹介します。\nなぜコピペでコーディングしてはいけないのか｜ DRY 原則 まずはじめに初心者の方向けに、そもそもなんで「コピー＆ペーストでコードを作っちゃダメ」なのかを簡単に説明します。 「そんなの当たり前だよ」という方はここは飛ばして次へ進んでくださいませ。\nプログラミングの原則として「コピー＆ペーストでコードを作っちゃダメ」というのがあります。これは「DRYの原則」と呼ばれています。 DRYは 「Don\u0026rsquo;t Repeat Yourself!」の略です。直訳すると「繰り返しはするな！」という感じでしょうか。\nこのDRYの原則は「達人プログラマー」という名著に説明があるかと思います。なぜコピペがダメなのかはこの本を読んでいただくのが一番良いです。\nリンク このDRY原則をものすごく簡単に説明しますね。例えばある処理を関数化せずにそのままべたっと10箇所にコピペしたとします。 コピペした直後は期待通り動作するでしょう。\nさて月日が経ち、この処理を修正する必要が発生したとします、コピペした10箇所全部にです。 仮に1箇所修正するときに間違いをしない確率を99%とします。では10箇所すべて修正するときにバグを出す確率（1つ以上間違えてしまう確率）は何パーセントでしょうか？\n(1 - 0.99^10) \\* 100 ≒ 10 となります。つまり約10％の可能性でバグるわけです。\n単に全く同じ機能をコーディングするだけでバグる確率が10％ってのは恐ろしく高い確率です。そして、どうせそのバグを修正するときにもまたバグりますよ。 無間地獄です。 ちなみにコピペが「職場文化」となっている場合、コピペ箇所が10個なんかではすみません。 あの処理を数十個コピペして、また別の処理を数十個コピペして……となるので、合計のコピペ数は爆発的に増えていきます。 コピペ自体は C-c C-v で一瞬で終わっちゃいますから爆速で増えていきます。\nちなみにコピペ箇所が300個あった場合（コピペが文化になっているとこのくらいはあっという間に増えます）、バグる確率は95％です。 それを修正しようとしてまたバグる確率まで考えると、目眩がしますね。いかにコピペが悪い文明かがご理解できたかと思います。\nPMD CPD で重複コードを検出する この悪しきコピー＆ペーストを検出するには、PMD CPDというツールを使います。 CPDは 「Copy/PasteDetector」の略です。インストールは簡単です。今回は Windows ＆ msys2環境で説明します。 Windows DOS や Mac、Linuxでもほぼ同じだと思います。\nまずは、Jenkinsで逐次実行させる前に、手動で動かしてみます。\nインストールする PMD の公式サイトにインストールの方法が書いてあります。 それをみて作業すればOKです。 Windowsの場合は、ダウンロードした zipを任意の場所に展開します。今回はc:\\Programs\\の下に展開することにします。\n実行してみる では早速実行してみます。サンプルとして μITORO準拠のTOPPERS/JSPのカーネルのコードに対して実行してみます。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 $ /c/Programs/pmd-bin-5.8.1/bin/run.sh cpd --minimum-tokens 100 --files ./kernel/ --language c --failOnViolation false Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\banner.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\check.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\cyclic.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\cyclic.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\eventflag.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\eventflag.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\exception.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\exception.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\interrupt.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\interrupt.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\jsp_kernel.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\jsp_rename.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\jsp_unrename.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\mailbox.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\mailbox.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\mempfix.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\mempfix.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\queue.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\semaphore.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\semaphore.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\startup.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\syslog.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\syslog.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\sys_manage.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\task.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\task.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\task_except.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\task_manage.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\task_sync.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\time_event.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\time_event.h Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\time_manage.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\wait.c Added C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\wait.h Found a 21 line (109 tokens) duplication in the following files: Starting at line 476 of C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c Starting at line 532 of C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c CHECK_DISPATCH(); CHECK_DTQID(dtqid); dtqcb = get_dtqcb(dtqid); t_lock_cpu(); if (dequeue_data(dtqcb, p_data)) { if ((tcb = receive_data_swait(dtqcb, \u0026amp;data)) != NULL) { enqueue_data(dtqcb, data); if (wait_complete(tcb)) { dispatch(); } } ercd = E_OK; } else if ((tcb = receive_data_swait(dtqcb, p_data)) != NULL) { if (wait_complete(tcb)) { dispatch(); } ercd = E_OK; } else { ===================================================================== Found a 20 line (102 tokens) duplication in the following files: Starting at line 477 of C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c Starting at line 533 of C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c Starting at line 582 of C:\\Users\\username\\work\\jsp-1.4.4.1-full\\.\\kernel\\dataqueue.c CHECK_DTQID(dtqid); dtqcb = get_dtqcb(dtqid); t_lock_cpu(); if (dequeue_data(dtqcb, p_data)) { if ((tcb = receive_data_swait(dtqcb, \u0026amp;data)) != NULL) { enqueue_data(dtqcb, data); if (wait_complete(tcb)) { dispatch(); } } ercd = E_OK; } else if ((tcb = receive_data_swait(dtqcb, p_data)) != NULL) { if (wait_complete(tcb)) { dispatch(); } ercd = E_OK; } else { このようにコピペのコードがあったファイルと、コピペコードを表示してくれます。 この例ではdataqueue.cにコピペがありますね。なかなか良いですね。\nJenkins で コピペコードを検出する さて、いよいよ Jenkins でこれらを逐次実行する方法です。 Jenkinsで実行することの利点は、自動実行という以外にも下記のようなメリットがあります。 見やすいのに加えて日々のコピペ量を計測してくれるので、メトリクスとしても使えそうです。\nPMD Plugin と Static Code Analysis プラグインをインストール まずは、Jenkinsに PMDのプラグインをインストールします。 「Jenkinsの管理」→「プラグインの管理」からプラグインマネージャーへ進んで、PMD Plugin をインストールしてください。\nもし Static Code Analysis Plug-ins がインストールされていなければこれもインストールしてください。 これは PMD以外のプラグインでもよく使われるものなのですでにインストールされているかもしれません。\nJenkins のビルドの設定で PMD CPD を有効にする これで Jenkins によって PMD CPD を使ってコピペされた重複コードを検出できるようになりました。 手順は簡単です。「ビルド後の処理の追加」にて、下記のように「重複コード分析の集計」というものが選べるようになっています。\nこれを選択しすると下記のような設定画面が出ます。いろいろな設定ができますが、ひとまずはデフォルトでいいでしょう。 「何行重複していたら指摘を出すか」など細かく設定できますので、使っていくうちにプロジェクトに合わせて調整すれば良いかと思います。\nJenkins PMD Plugin の実行結果の例 上記の設定をしてビルドすると、下記のように結果が表示されます。いろいろなビューがありますのでいろいろ見てみると良いですね。 ちなみに以下の図では重複コードのあるファイル名と重複コードの行数が表示されています。\nそして上記のファイル名のところをクリックすると、下記のように重複コードを表示してくれます！ 視覚的に一発でどんなコピペコードがわかるので大変便利です！！！これでどんどん重複コードを撲滅できますね！\nまた、これらの結果の推移も自動で集計してくれます。例えば重複コードの個数の遷移をグラフ化したり「今回のビルドで新規に発生した重複コードはここ」とか教えてくれたりとか。 重複コードの撲滅に大変有用です！\nNote\nもし重複コードが表示されない場合は、Content Security Policy （CSP）が原因かもしれません。 例えば JenkinsのClover pluginを利用したカバレッジレポートページにCSSが適用されない に解説がありますので、参考にして見てください。対応自体は簡単ですよ。\nまとめ 今回はコピペで作られた重複コードの害と、それを逐次検出するための Jenkins と PMD CPDについて説明しました。重複コードはコード品質を著しく下げますので、今回の記事を元にどんどん減らしていって見てください！ しょうもないバグや修正が減ると思います！\n","permalink":"https://nagayasu-shinya.github.io/posts/jenkins-duplicate-code-detection/","summary":"\u003cp\u003eJenkinsとPMD CPDを使って、コピペコード（重複コード）を継続的に検出・監視する方法を説明します。\u003c/p\u003e","title":"コピペコードを逐次検出する｜Jenkins と PMD CPD"},{"content":"組み込みソフトではよくある２の累乗の値への切り上げについて例を交えて説明します。\n今回は2の累乗の値への切り上げ＆切り捨てについて、効率的なC言語のコードの書き方をご紹介します。 組み込みファームウェアでは、2の累乗への丸めをする必要がままあります。 例えばメモリのページサイズは2の累乗（0x1000 Byteとか）なので、必要なページ数を計算したりするのに使用します。\nまずは手始めに、一般的な10の累乗での切り上げ＆切り捨ての方法を紹介します。そのあと、2の累乗での切り上げ＆切り捨ての方法をご紹介します。\n10の累乗での切り上げ＆切り捨て まずは手始めに、普通の10進数での切り上げ＆切り捨てを確認します。言い換えると、10の累乗（10, 100, 1000, 10000\u0026hellip;.）にて切り上げる処理です。 例えば 1234 という値を100 で切り上げたとき＆切り捨てたときはどうなるでしょう？ 切り捨てた場合は1200, 切り上げた場合は1300ですね。見ただけですぐできますね。\n一般化するために式で書いてみる パッと見て暗算できるんですが、ここはせっかくなので式にして一般化して見ましょう。C言語で書くと下記のようになります。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; int main(void) { unsigned int val = 1234u; /* 元の値 */ unsigned int ceil_val; /* 切り上げた値 */ unsigned int floor_val; /* 切り捨てした値 */ unsigned int nth_power = 100u; /* 10の累乗 */ /* 切り捨て */ floor_val = val - (val % nth_power); /* 切り上げ */ ceil_val = (val + (nth_power - 1)) - ((val + (nth_power - 1)) % nth_power); printf(\u0026#34;val : %d.\\n\u0026#34;, val); printf(\u0026#34;floor_val : %d.\\n\u0026#34;, floor_val); printf(\u0026#34;ceil_val : %d.\\n\u0026#34;, ceil_val); return 0; } 切り捨てコードの処理の解説 切り捨てについては、簡単ですね。1234 という値を 100 で切り捨てるときは、元の値 1234 から 34 を引けばいいです。34の求め方は、1234 を 100で割ったときの余りです。余りの計算（剰余算）は「％演算子」でできます。\nということで切り捨ては、1234 を val、100 を nth_power という変数名にすると、 val - (val % nth_power); という式で計算できます。\n切り上げコードの処理の解説 次は切り上げについて見ていきます。 1234 という値を 100で切り上げるときの考え方としては「100の位を1増やしてから切り捨てをする」とすればOKです。言い換えると、1234 に 100 を足して切り捨てをすると、元の値を切り上げした値 1300 となります。\n1234 を val、100 を nth_power という変数名としてC言語で書くと、 (val + nth_power) - ((val + nth_power) % nth_power); となります。\nこれでも問題なさそうですが、実は1点まずいところがあります。もし元の値valが10の累乗だった場合に問題が起きます。 例えばvalが1200だった場合、これを切り上げた値は1200のままです、すでにキリのいい値になっていますから、なにもする必要はありません。\nですが上記の式で計算した場合、結果は1300になってしまいます。 もともと、100 で切り上げるときの考え方としては「100の位を1増やしてから切り捨てをする」というものでした。ですが、正確には「元の値が100の累乗でない場合のみ、100の位を1増やしてから切り捨てをする」とする必要があります。\n上記式では、100の位を1増やすために nth_power（100）を足していますが、元の値のときは100の位を変更しないようにするため、nth_power（100）から1を引いたものを足すようにします。\n(val + (nth_power - 1)) - ((val + (nth_power - 1)) % nth_power);\nこれで正しく切り上げすることができるようになります。\n2の累乗への切り上げ＆切り捨て さて、本題の2の累乗への切り上げ＆切り捨てを考えます。 2の累乗（0x2, 0x4, 0x8, 0x10, 0x20,\u0026hellip;.）にて切り上げる処理です。 例えば 0x1234 という値を0x0100で切り上げたとき＆切り捨てたときはどうなるでしょう？ 切り捨てた場合は0x1200, 切り上げた場合は0x1300ですね。これも見ただけですぐできますね。\n2の累乗でも式で書いてみる 2の累乗でも、実は10の累乗と同じ式で切り捨て＆切り上げができます。C言語で書くと下記のようになります。値とprintfのフォーマットを変えただけです。処理は全く変えていません。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; int main(void) { unsigned int val = 0x1234u; /* 元の値 */ unsigned int ceil_val; /* 切り上げた値 */ unsigned int floor_val; /* 切り捨てした値 */ unsigned int nth_power = 0x0100u; /* 2の累乗, 1u \u0026lt;\u0026lt; 8 */ /* 切り捨て */ floor_val = val - (val % nth_power); /* 切り上げ */ ceil_val = (val + (nth_power - 1)) - ((val + (nth_power - 1)) % nth_power); printf(\u0026#34;val : 0x%04x.\\n\u0026#34;, val); printf(\u0026#34;floor_val : 0x%04x.\\n\u0026#34;, floor_val); printf(\u0026#34;ceil_val : 0x%04x.\\n\u0026#34;, ceil_val); return 0; } 2の累乗に合わせて最適化 上記のように剰余算を使えば切り捨て＆切り上げができます。ですが、コードサイズと処理速度的にはイマイチです。だって2の累乗なので2進数と親和性が高いんですから！つまりビット演算を使いやすいということですね！早速C言語のコードを示します。このように剰余算などの重い処理を使わずに処理できます！\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; int main(void) { unsigned int val = 0x1234u; /* 元の値 */ unsigned int ceil_val; /* 切り上げた値 */ unsigned int floor_val; /* 切り捨てした値 */ unsigned int nth_power = 0x0100u; /* 2の累乗, 1u \u0026lt;\u0026lt; 8 */ /* 切り捨て */ floor_val = val \u0026amp; ~(nth_power - 1); /* 切り上げ */ ceil_val = (val + (nth_power - 1)) \u0026amp; ~(nth_power - 1); printf(\u0026#34;val : 0x%04x.\\n\u0026#34;, val); printf(\u0026#34;floor_val : 0x%04x.\\n\u0026#34;, floor_val); printf(\u0026#34;ceil_val : 0x%04x.\\n\u0026#34;, ceil_val); return 0; } コードの処理内容は、ちょっと頭の体操と思って考えて見てください。慣れればどうってことはない処理です。 不明点あればコメント欄に書いていただければ、わかる範囲でお答えします！ 最適化したコードとどのように差があるかは、 超便利！C言語のアセンブラ出力を即確認できるサイト｜compiler-explorer の記事を参考に出力されたアセンブラを確認すると良いです。\nまとめ 今回は2の累乗への切り上げ＆切り捨てをC言語で処理する方法をご紹介しました。2の累乗はビット演算と親和性が高いので、ビット演算を使い効率的なコードを書くことができます。ファームウェアではコードサイズを小さくする必要がおうおうにしてありますので、このようなテクニックも覚えていて損はないと思います。\nまた、10の累乗への切り上げ＆切り捨ても説明しました。こちらは剰余算を使います。こちらはご参考までに。 ちなみにこの記事は下記の本を参考にしました。\nリンク ","permalink":"https://nagayasu-shinya.github.io/posts/power-of-two-rounding/","summary":"\u003cp\u003e組み込みソフトではよくある２の累乗の値への切り上げについて例を交えて説明します。\u003c/p\u003e","title":"C言語で2の累乗（2^n）への切り上げ＆切り捨て"},{"content":"C/C++にて特定のサイズでアライメントされた領域を確保する方法を説明します。\nC/C++でコーディングしていると、特定のサイズにアライメントされた領域が必要になることがありますよね。ハードウェアに近いところを実装してると「4KiBでアラインせよ」とか普通にありますね。 このようなアライメントされた領域を確保する方法はいくつかありますが、今回は可搬性の高い方法をいくつか紹介します。\nposix_memalign 関数 これは名前の通り、POSIX準拠の関数ですので Unixや Linux などほとんどの環境で動作します。 プロトタイプ宣言はint posix_memalign(void **memptr, size_t alignment, size_t size);です。 この関数は、引数 size（Byte）の大きさの領域を確保し、引数 memptrの指す先へ領域へのポインタを格納します。 その領域は引数 alignmentで指定した値でアライメントされています。 また、alignment の値は 2の冪乗および sizeof(void *)の倍数である必要があります。 確保に成功した場合は0を返します。\nmallocと違い、戻り値でなく引数のポインタ渡しにて確保した領域のポインタを受け取ることに注意が必要です。 posix_memalign() で確保した領域は、malloc() と同じようにfree()関数で解放できます。\n使用例を示します。0x400でアライメントされた0x1000 Byte の領域を確保する例です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; // posix_memalign を使うときに必要 #define ALIGN_VAL (0x00000400) #define DATA_SIZE (0x00001000) int main(void) { int *ptr; if (posix_memalign(\u0026amp;ptr, ALIGN_VAL, DATA_SIZE) != 0) return 1; // error. *ptr = 0xdeadbeef; printf(\u0026#34;val:0x%08x, addr:%p\\n\u0026#34;, *ptr, ptr); free(ptr); return 0; } /* 出力は例えば * val:0xdeadbeef, addr:0x97a400 * となる。addr がアライメントされているはず。 */ aligned_alloc 関数 これはC++17 およびC11にて言語規格に採用される関数です。 と言っても、gccだったら普通に使用可能です。 プロトタイプ宣言はvoid *aligned_alloc(size_t alignment, size_t size); です。\nこの関数は、引数size（Byte）の大きさの領域を確保しそのポインタを返します。 その領域は引数alignment で指定した値でアライメントされています。 また、alignmentの値は 2 の冪乗および sizeof(void *)の倍数である必要があります。 確保に成功した場合は0を返します。さらに、引数 size は 引数 alignment の倍数である必要があります。 これは前述のposix_memalign 関数にはない制約です。 mallocと同様に戻り値で確保した領域のポインタを受け取ります。 そのためmalloc からの移行は posix_memalign に比べ簡単かもしれません。 aligned_alloc() で確保した領域は、malloc() と同じようにfree()関数で解放できます。\nposix_memalignと同様に使用例を示します。0x400でアライメントされた0x1000 Byte の領域を確保する例です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; // aligned_alloc を使うときに必要 #define ALIGN_VAL (0x00000400) #define DATA_SIZE (0x00001000) int main(void) { int *ptr; if ((ptr = aligned_alloc(ALIGN_VAL, DATA_SIZE)) == NULL) return 1; // error. *ptr = 0xdeadbeef; printf(\u0026#34;val:0x%08x, addr:%p\\n\u0026#34;, *ptr, ptr); free(ptr); return 0; } /* 出力は例えば * val:0xdeadbeef, addr:0x97a400 * となる。addr がアライメントされているはず。 */ alignas キーワード（C++11 or later） これはC++11以降の機能ですのでC言語では使えません。 ですが上記２つの関数のようにアロケータを使うわけでなく変数定義のときにキーワードを指定するだけですのでとてもお手軽です。 freeする必要もないのでメモリリークの心配もありません。 ある関数内でのみ領域が必要な場合はこれを使うのが楽でしょう。\n今回も使用例を示します。0x400でアライメントされた0x1000 Byte の領域を確保する例です。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include \u0026lt;siostream\u0026gt; #include \u0026lt;scstdlib\u0026gt; int main() { constexpr auto align_val = 0x00000400; constexpr auto data_size = 0x00001000; alignas(align_val) int tmp[data_size / sizeof(int)]; static_assert(0 == ((uintptr_t) \u0026amp;tmp \u0026amp; (align_val - 1)), \u0026#34;?? ERR alignment\u0026#34;); tmp[0] = 0xdeadbeef; printf(\u0026#34;val:0x%08x, addr:%p\\n\u0026#34;, tmp[0], \u0026amp;tmp); } /* 出力は例えば * val:0xdeadbeef, addr:0x7fff241c2800 * となる。addr がアライメントされているはず。 */ おまけ 標準ライブラリ malloc のアライメント C言語には標準ライブラリにmalloc関数がありますよね。 この関数の返す領域のアドレスのアライメントはどうなっているのでしょうか？\n調べてみたところ、C言語規格 JIS X3010 (いわゆるC99)に言及がありました。\n割付けが成功したときに返されるポインタはいかなる型のオブジェクトへのポインタに代入してもよいように，またその割り付けられた領域のオブジェクト又はオブジェクトの配列へのアクセスに使用してもよいように適切に境界調整されているものとする\nちょっとわかりづらいですが、思い切って意訳すると「どんな型にキャストしても大丈夫なようにアライメントしたアドレスを返すよ！」ということですね。 例えば32bit ARM だと、4Byte境界にアライメントされたアドレスになります。（long long 型も4Byteの2回アクセスになります）\nNote\nもしC言語規格（C99）をもっと知りたい場合は、JISの公式サイトにてPDFファイルを閲覧できます。「X3010」で検索してください。ちなみに、ダウンロードは残念ながらできません。閲覧のみです。\nまとめ 今回は、C/C++にてアライメントされた領域を確保する方法を説明しました。 ついでに標準関数malloc のアライメントの仕様（JIS X3010,C99）についても書いておきました。 基本的には aligned_alloc()を使うのが良いかと思います。 C11およびC++17規格に準拠していますし、関数の使い方がmalloc に似ているためです。\nC++である関数内でだけアライメントされた領域が必要なときはalignasキーワードがオススメです。 変数定義時に指定するものなので、free()を呼ぶ必要がありません。 変数ですので関数を抜ければ勝手に解放されます。メモリリーク漏れが防げます。\n上記が使えない場合はposix_memalign()の使用を検討してみてください。 malloc() やaligned_alloc()と違いダブルポインタを使う必要があったり確保した領域の取得の仕方が違ったりと少し癖がありますが、POSIX準拠なので、大抵の環境で動くはずです。 以上、C/C++にてアライメントされた領域を確保する方法でした！\n","permalink":"https://nagayasu-shinya.github.io/posts/memory-aligned-allocation-posix/","summary":"\u003cp\u003eC/C++にて特定のサイズでアライメントされた領域を確保する方法を説明します。\u003c/p\u003e","title":"C/C++でアライメントされた領域を確保する方法｜aligned_alloc, posix_memalign, alignas"},{"content":"オンラインでさまざまな言語のコンパイル・実行ができる Wandboxという便利サイトの紹介です。\n超便利！C言語のアセンブラ出力を即確認できるサイト｜compiler-explorer で Compiler Explorerというサイトを紹介しました。 これはC/C++やRust、Go言語のコンパイル結果（アセンブラ出力）をオンラインで確認できるものでした。 今回の Wandbox は、アセンブラ出力でなく実行結果を確認するものです。多くの言語（30以上！）に対応しています。\nWandboxとは Wandbox は、オンラインでさまざまな言語のコンパイル・実行ができるサービスです。その場でサクッとプログラムを動かせるので便利です。やたらめったらに多くのコンパイラのバージョンに対応していて、各バージョンでの動作差異に重宝します。他にも新しい言語を勉強したいときに、開発環境を構築する前の味見として使えるかと思います。慣れない言語だと環境構築だけで心が折れたりしますからね。。。 内部の仕組みに興味のある人は Wandbox の GitHub リポジトリ を参照してみてください。Yesod という Haskell の Web フレームワークで作ってるそうです。\nさわってみよう さっそくさわってみましょう。と言っても、特に説明することがないくらいシンプルかつわかりやすいです。 まずはWandboxへアクセスしましょう。アイコンというか「三へ(へ՞ਊ ՞)へﾊｯﾊｯ」という微妙にキモい絵文字が見えるかもしれませんが気にしないことにしましょう。作者さんの遊び心なんでしょう、きっと。。。\n下記のような構成です。これを見ればほぼ使い方はわかるかと思いますが、簡単に説明しますね。\n真ん中の main 関数があるところに、試したいコードを上書きします。 初期状態は、 C++で Hello, Wandbox!と表示するサンプルプログラムが書かれています。\n左の列で言語とコンパイラ、オプションを選択します。上記の画像では gcc HEAD 7.01が選択されていますね。 他に最適化オプション（Optimize）やBoost、C++のバージョンなど選べるようになっています。 さらに細かい設定を追加したい場合は「Compiler Options:」とあるボックスに自由にコンパイラオプションを記述できます。\nあとは真ん中のコード下にあるボタン「Run (or Ctrl+Enter)」を押します。するとコンパイル＆実行処理されます。サンプルコードのままの場合は上の画像のように Hello, Wandbox!と表示されるはずです。 もしコンパイルエラーがあれば通常のコンパイラと同様にエラーメッセージが表示されます。\nもし自分が書いたコード＆設定を他の人とシェアしたい場合は、ボタン「Run (or Ctrl+Enter)」のすぐ下にある「Share this code」というボタンを押します。 すると、下記のようにTwitter でのシェアかリンクアドレスかどちらかを選択できます。\n参考までに2017-04-04時点での対応言語を列挙します。聞いたことない言語もありますね！充実すぎるラインナップ！！\nBash script Lua C Nim C# OCaml C++ OpenSSL CPP PHP CoffeeScript Pascal Crystal Perl D Pony Elixir Python Erlang Rill Go Ruby Groovy Rust Haskell SQL Java Scala JavaScript Swift Lazy K Vim script Lisp また、それぞれの言語に対して複数のコンパイラおよびコンパイラバージョンに対応しています。 例えばCやC++ならば、GCCやClangがあります。また、それぞれのコンパイラのバージョンまで指定できます。下記のような感じです。\nまとめ 今回はWeb上ですぐにC言語やC++,その他約30言語以上のプログラムをその場で実行できるサイト Wandboxを紹介しました。 多くのコンパイラ、バージョンに対応していますので各コンパイラバージョンでの挙動の差異の確認に便利です。 また、新しい言語を始めるときのとっかかりとしても有用そうです。ぜひご活用くださいませ！\n","permalink":"https://nagayasu-shinya.github.io/posts/online-compiler-wandbox/","summary":"\u003cp\u003eオンラインでさまざまな言語のコンパイル・実行ができる \u003ca href=\"https://wandbox.org\"\u003eWandbox\u003c/a\u003eという便利サイトの紹介です。\u003c/p\u003e","title":"超便利！C/C++他30種類のプログラムをその場で実行確認できるサイト｜Wandbox"},{"content":"Excel起動時に「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」とか「プロジェクトまたはライブラリがみつかりません」とか怒られた場合の対処法を説明します。\nWindows7 64bit ＆ Excel 2010 にて、ExcelでPictMasterOAを使おうとしたら、 起動時に VBAで「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」とか「プロジェクトまたはライブラリがみつかりません」とか怒られて起動できませんでした。\nその解決方法を調べたので、公開します。 PictMasterOA に限らず、Windows 64bit を使っていると起こる可能性のある問題のようです。 もし同様の問題が起きたら、試してみてください。\n「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」 Excelを起動すると、「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」というダイアログがポップアップされます。 なんのこっちゃ。\nC言語でいうナル文字列を参照しちゃったような感じのエラー文ですね。おそらく主語にあたる何かが見つけられないのでしょう。\n「プロジェクトまたはライブラリがみつかりません」 今度は VBE(Visual Basic Editor)が開き、「プロジェクトまたはライブラリがみつかりません」というエラーが出ます。どうも VBA の Trim 関数が見つからないようです。\n何度か再実行してみても、同じエラーが出ます。はてさて。\n必要なファイル MSCOMCTL.OCX をダウンロード いろいろ調べた結果、MSCOMCTL.OCXというものを参照できていないのが原因のようです。\nVBEの「ツール」→「参照設定」をクリックしてみます。すると、下記のようにエラーが出ています。 もし、「参照設定」がひらけない場合は、デバッガが動作している可能性があります。停止ボタンを押してデバッガを止めてください。音楽プレーヤーと同じようなアイコンです。下図では赤丸で囲んでいます。\nこいつを参照できるようにしましょう。MicrosoftのMicrosoft Visual Basic 6.0 コモンコントロールから.exeファイルをダウンロードします。 VisualBasicXXXXXX.exeというのがダウンロードできたかと思います。\nダブルクリックすると何かが実行されて「更新できました！」とダイアログが出ます。 それで問題が解決する人もいるそうですが、私の場合は解決できませんでした。症状変わらず……\nexeファイルから自力で必要なファイルを抜き出そう 本当はVisualBasicXXXXXX.exeを実行したら C:\\Windows\\system32\\ か C:\\Windows\\SysWoW64\\あたりにお目当のMSCOMCTL.OCXを展開して欲しかったのですが、 どうもやってくれない場合もあるようです。 そこで、 .exe から該当ファイルを抜き出して自分で処理することにします。\nまず、exeファイルからファイルを抽出する方法です。 いろいろなツールがありますが今回はオープンソースの 7-Zip を使った方法を説明します。\nWarning\n同じことができるツールがいくつかありますが、ライセンスに気をつけてくださいね。企業では無料では使えないものもあります\nまず、7-Zip 紹介（窓の杜） からインストーラをダウンロードします。そして、えいやっとインストールします。ぽちぽち押していけば大丈夫です。\nインストールが終わったら、早速 exeファイルを展開します。 exeを右クリックして展開できます。下記の図を参考にしてみてください。\n展開したファイルの中にMSCOMCTL.OCXというファイルがあると思います。 こいつをC:\\Windows\\SysWoW64\\ へコピーします。\nさらにこいつを regsvr32で処理します。 コマンドプロンプトを 管理者権限で開いて、regsvr32 MSCOMCTL.OCX とコマンドを叩きます。 すると「mscomctl.ocxのDllRegisterServerは成功しました」とポップアップが出ます。下記の図を参考にやってみてください。\nこれで、MSCOMCTL.OCXが使える準備ができました。あとはExcel側の設定です。\nExcelの参照ライブラリの設定 MSCOMCTL.OCX を参照する設定をします。Excelを開いてVBE(Visual Basic Editor) を開きます。 ショートカットキー Alt＋F11 を押すか、「開発」→「Visual Basic」と押します。するとVBEが開きます。\n次にVBEにて、「ツール」→「参照設定」をクリックしてください。参照しているライブラリ一覧が出ると思います。ここで「Microsoft Windows Common Controls 」を選択してください。 そして右の「参照」ボタンを押して C:\\Windows\\SysWoW64\\MSCOMCTL.OCXを選択してください。そしてOKを押してください。\n当初は「参照不可」となっているはずですが、今回は下記のように無事に参照できるはずです。 もし、「参照設定」がひらけない場合は、デバッガが動作している可能性があります。停止ボタンを押してデバッガを止めてください。音楽プレーヤーと同じようなアイコンです。下図では赤丸で囲んでいます。\nあとはExcelを再起動すれば、無事にエラーが出なくなっているはずです！\nまとめ 今回はExcelで動くツールPictMasterOAを例に、 64bit Windowsにて「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」とエラーが出る場合、「プロジェクトまたはライブラリがみつかりません」と言われる場合の解決方法を説明しました。 PictMasterOAに限らず、VBAを使っている場合は起きうる問題です。同じようなエラーが出た際はぜひ参考にしてみてくださいね！\nNote\nPictMasterOA さまのブログに「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」の対処法として対処法が投稿されました！\n","permalink":"https://nagayasu-shinya.github.io/posts/excel-vba-library-error-64bit/","summary":"\u003cp\u003eExcel起動時に「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」とか「プロジェクトまたはライブラリがみつかりません」とか怒られた場合の対処法を説明します。\u003c/p\u003e","title":"Excelで「はこのマシンでは利用できないため、オブジェクトを読み込めませんでした」が出たときの対処法"},{"content":"Compiler Explorerは、オンライン上でC/C++等のコードをコンパイルし、アセンブラ出力をリアルタイムで確認できる便利なサイトです。\n先日、C言語のコードをアセンブラ出力を確認しながら最適化するという記事を投稿しました。 このときアセンブラ出力は実際にgccを使ってアセンブラを出力していました。\nこの記事のコメント欄にて buchio さんから素晴らしく便利なサイト compiler-explorer をお教えいただきましたのでご紹介いたします。 buchioさん、ありがとうございます！\ncompiler-explorer とは その便利サイトとは、Web上ですぐにC言語をアセンブラにしてくれるCompiler Explorer です。 どんなサイトかを GitHub の Ｗiki からの抜粋します。\nCompiler Explorer is an interactive tool that lets you type code in one window and see the results of its compilation in another window.\nものすごくざっくりと意訳するとこんな意味ですね。\nCompiler Explorer は入力されたコードのコンパイル結果をその場で表示するよ！\nより詳細な説明は README を参照してください。現時点（2017-02-16）で C/C++、Rust、D言語、Go言語 に対応しているようです。\nどんなものか見てみよう まず Compiler Explorerへアクセスしてください。 こんなサイトが表示されたかと思います。\nサンプルコードとして引数を二乗する関数 square が書かれていますね。 左のウィンドウにC言語のコード、右にコンパイル結果のアセンブラがあります。 コンパイラは x86-64 gcc 6.3 に設定してありますね。 このように、基本的な使い方は、左のウィンドウにC言語のコードを書いて右側のアセンブラを確認する、となります。\n実際に使ってみよう さて、実際に使って見ましょう。サンプルコードは C言語のコードをアセンブラ出力を確認しながら最適化する で使ったものを使います。\nこれが実行結果です。今回はウィンドウが３つありますね。 左はC言語、真ん中は最適化オプションが -O0、右側は最適化オプションが -O2です。 このように、１つのC言語のコードに対し同時にいろんなコンパイラオプションでのアセンブラを同時に表示できます！ 一目で最適化が効いているのがわかりますね！\nC言語のコードとアセンブラの対応もわかるようになっています。左のC言語のウィンドウの背景色が緑、黄、紫、赤の4色ありますね。 真ん中のアセンブラも緑、黄、紫、赤の4色ありますね。それぞれC言語の同じ背景色に対応しています。 どこのコードがどのようにコンパイルされたか一目でわかります！ また、右の最適化をかけたアセンブラは背景色が黄、赤の2色しかありません。最適化により緑と紫のC言語コードが削除されたことを示しています。\n細かい使い方は実際に触ってればすぐわかると思います。わからなかったら、アイコンの上にマウスオーバすると説明がポップアップするので大丈夫です。\nまとめ 今回はWeb上ですぐにC言語をアセンブラにしてくれるサイトCompiler Explorerを紹介しました。 同時に複数の最適化オプションの結果を表示したり、どのC言語コードがどのアセンブラに対応するかなど一目でわかります！ 実行速度やコードサイズがシビアな環境で開発している人にとってはとても役立つサイトだと思います！ぜひご活用くださいませ！\n","permalink":"https://nagayasu-shinya.github.io/posts/compiler-explorer-online/","summary":"\u003cp\u003eCompiler Explorerは、オンライン上でC/C++等のコードをコンパイルし、アセンブラ出力をリアルタイムで確認できる便利なサイトです。\u003c/p\u003e","title":"超便利！C言語のアセンブラ出力を即確認できるサイト｜compiler-explorer"},{"content":"RelaxToolsはExcelに250以上の機能を追加する無料アドインです。Redmine連携やマクロ支援など、業務効率化に役立ちます。\nみなさん、MＳ Excel使ってますか？もはやデータ処理やグラフ作成の必需品といえますよね。 長時間Excelで作業をしている人も多いかと思います。より効率的に作業をするため、マクロやVBAを自作しているかたもいらっしゃると思います。 ただ、自作はめんどくさいなぁという気持ちもありますよね。そういう時は既存のアドインを使うのもアリですね。 ということで、Excelのとても便利で素敵なアドインRelaxTools Addinをご紹介します。\nRelaxTools Addin てどんなの？ このRelaxTools Addin、 なんと250以上の機能があるそうです！8bitじゃ足りないくらいの機能数ですね！ 公式サイトから機能を一部抜粋してみます。盛りだくさんすぎてどれを抜粋するか悩むレベル。\nExcelブック内部のGrepが可能 Excel表をHTML変換（Excelをデザイナとして利用可能） シェイプ内の文字列またはセルの正規表現検索および置換 職印機能 付箋作成機能 Excel/Word/PowerPointのページ数カウント VBAのステップカウント セルの重複チェック／文字数／バイト数の確認 半角／全角／数値／英字／英数字／日付チェックおよび主なチェックデジットチェック等 セルの前後のトリム／文字挿入／文字削除／改行削除 等 TortoiseSVN/Git対応 Textile, Markdown 変換 他には、例えば、Excelの謎仕様「違うフォルダにある、同じ名前のファイルを開くことができない」も解決してくれるようです 「同名のExcelファイルを開きたい！」に解説があります。 （Microsoft はいつになったらこの仕様、修正するんだろう……）\n上記に挙げたように硬派で真面目な機能がたくさんのツールなんですが、ときどき中の人の遊び心があって、それも楽しいですね！ 例えばこんなの。媚びていきたいですね。寿司食べたいですね。\n上司に媚びることが可能となった認め印機能 Excel にもスシを流してみた 使用例｜Excelの表をRedmineへコピーする RelaxTools Addin はさまざまな機能がありますが、例としてExcelで書いた表をRedmineにコピーする方法を紹介します。 Redmineはtextile記法を採用しています。これ、表を書くのが結構めんどくさいんですよね、中央寄せとかセルの背景色を設定するのとか。 ですが大丈夫、RelaxTools Addin を使えば楽に表作成できます！ RelaxTools Addin をインストールすると下記のようにタブがたくさん増えます。 この中の「Relax Apps」タブをクリックします。すると下記のリボンが表示されます。 Redmineのアイコンがありますね。これを使えばtextile形式に変換できるのです！\n変換したい表を選択して、Redmineロゴのボタンをクリックします。すると、textile形式に変換された表が別ウィンドウで表示されます！\nあとはこれをRedmineのチケットやWikiに貼り付ければ、綺麗な表の出来上がりです！ セルの塗りつぶしやセンタリングもちゃんとできています！素晴らしい！\nインストール方法 インストールは別に難しくありません。基本、ぽちぽちボタンを押していくだけ。 ただ、一箇所だけ間違えそうなところがあります。\nまずは公式サイトの説明をみて、zipファイルをダウンロードします。 zipファイルを解凍すると下記のようなファイルが入っています。この中のinstall.vbsを実行すればいいです。\nなにかいろいろとウィンドウが開きますが、ぽちぽち押していけば大丈夫です。\n注意点はここです！プロパティの設定ウィンドウが自動で開かれます。ここで「ブロックの解除」ボタンをクリックしてから次に進んでください！\nあとはまたボタンをぽちぽち押していけば大丈夫です。\nインストールに成功すると、Excelを開いたときにメニューが増えているはずです。 下の図で赤枠で囲んだところが、追加されたアドインの機能です。\nということで、インストールはとても簡単です。ただ、散漫とボタンをぽちぽちしていると「ブロックの解除」を忘れてまうので、そこだけ注意してくださいね。\nまとめ 今回は素敵便利なExcelのアドイン「RelaxTools Addin」のご紹介でした。 編集機能の強化だけでなく、TortoiseSVN/Git に対応してたりRedmine textileや Markdown、HTML出力も対応してたりと便利すぎますね！\n","permalink":"https://nagayasu-shinya.github.io/posts/excel-relaxtools-addon-utilities/","summary":"\u003cp\u003eRelaxToolsはExcelに250以上の機能を追加する無料アドインです。Redmine連携やマクロ支援など、業務効率化に役立ちます。\u003c/p\u003e","title":"Excelの素敵アドイン「RelaxTools Addin」でRedmineの表作成もカンタンに！"},{"content":"C言語のループ処理を3種類の書き方でアセンブラに変換し、どの書き方が効率の良い機械語を生成するか比較します。\n最近のパソコンでは、CPUは高速でメモリもたくさんあるので、プログラマが頑張って高速な機械語を吐くように意識したコードを書くことはあまりありません。ですが、組み込みの世界ではまだまだCPUもメモリも貧弱な環境がたくさんあります。高速なCPUや大きいメモリはそのまま原価に跳ね返るためです。\nそこで今回は、高速な機械語を吐くC言語のソースコードを書く練習をしてみます。やり方は、3種類の100回ループするC言語のソースコードを、それぞれアセンブラに変換して、どのくらい効率が良くなるか比較してみます。\nコンパイルしたコードのアセンブラの確認 C言語のソースコードをgcc -O2 -c hoge.c -o hoge.oのようにコンパイルすると、通常はオブジェクトファイル（.o）に変換されます。\nこれを、オブジェクトファイルでなくアセンブラのコードに変換するにはgcc -O2 -S hoge.c のように-S オプションを使います。すると .sのアセンブラファイルが生成されます。\nまた、gccならgcc -O2 -save-temps hoge.cの形でもOKです。これはアセンブラ.s ファイル以外に、プリプロセス済みファイルの.iファイルも生成する優れものです。\n今回はこの-save-temps オプションを使用します。\nインクリメントなforループ 一般的なforループで書いてみます。\n1 2 3 4 5 6 7 8 9 10 11 #define LOOP_NUM (100) int main(void) { volatile int i; for (i = 0; i \u0026lt; LOOP_NUM; i++) ; return 0; } このコードを gcc -O2 -save-temps for_incr.cにてコンパイルすると、下記のようなアセンブラが出力されます。13命令ですね。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .align 4, 0x90 _main: ## @main .cfi_startproc ## BB#0: pushq %rbp Ltmp0: .cfi_def_cfa_offset 16 Ltmp1: .cfi_offset %rbp, -16 movq %rsp, %rbp Ltmp2: .cfi_def_cfa_register %rbp movl $0, -4(%rbp) movl -4(%rbp), %eax cmpl $99, %eax jg LBB0_2 .align 4, 0x90 LBB0_1: ## %.lr.ph ## =\u0026gt;This Inner Loop Header: Depth=1 incl -4(%rbp) movl -4(%rbp), %eax cmpl $100, %eax jl LBB0_1 LBB0_2: ## %._crit_edge xorl %eax, %eax popq %rbp retq .cfi_endproc .subsections_via_symbols デクリメントなforループ 次はデクリメントなforループで書いてみます。たまに「デクリメントループは読みにくいからやめるべし」という方もいますが、まあ、組込み屋ならパッとみて理解できた方が良いかなと思います。\n1 2 3 4 5 6 7 8 9 10 11 #define LOOP_NUM (100) int main(void) { volatile int i; for (i = LOOP_NUM; i; i--) ; return 0; } このコードを gcc -O2 -save-temps for_decr.cにてコンパイルすると、 下記のようなアセンブラが出力されます。10命令に減りましたね！\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .align 4, 0x90 _main: ## @main .cfi_startproc ## BB#0: pushq %rbp Ltmp0: .cfi_def_cfa_offset 16 Ltmp1: .cfi_offset %rbp, -16 movq %rsp, %rbp Ltmp2: .cfi_def_cfa_register %rbp movl $100, -4(%rbp) jmp LBB0_2 .align 4, 0x90 LBB0_1: ## %.lr.ph ## in Loop: Header=BB0_2 Depth=1 decl -4(%rbp) LBB0_2: ## %.lr.ph ## =\u0026gt;This Inner Loop Header: Depth=1 cmpl $0, -4(%rbp) jne LBB0_1 ## BB#3: ## %._crit_edge xorl %eax, %eax popq %rbp retq .cfi_endproc .subsections_via_symbols デクリメントなdo-whileループ 次はデクリメントなdo-whileループで書いてみます。 これは組込屋さんでもぱっと見では少しわかりづらいかもしれません。 コメントで「高速化のためにあえてやっている」という旨を書いておくといいかもしれません。\n1 2 3 4 5 6 7 8 9 10 11 12 #define LOOP_NUM (100) int main(void) { volatile int i = LOOP_NUM; do { ; } while (--i); return 0; } このコードを gcc -O2 -save-temps do_while.cにてコンパイルすると、下記のようなアセンブラが出力されます。8命令に減りましたね！素朴なforインクリメントループの13命令から比べるとだいぶ減りました！！！\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .align 4, 0x90 _main: ## @main .cfi_startproc ## BB#0: pushq %rbp Ltmp0: .cfi_def_cfa_offset 16 Ltmp1: .cfi_offset %rbp, -16 movq %rsp, %rbp Ltmp2: .cfi_def_cfa_register %rbp movl $100, -4(%rbp) .align 4, 0x90 LBB0_1: ## =\u0026gt;This Inner Loop Header: Depth=1 decl -4(%rbp) jne LBB0_1 ## BB#2: xorl %eax, %eax popq %rbp retq .cfi_endproc .subsections_via_symbols まとめ 今回はループ文を例に、高速な機械語を吐くようなC言語のコードを書いてみました。このように、実際にC言語のソースコードを修正してアセンブラを確認して、、、というのを繰り返してコードを最適化できます。組み込みでは1Byte単位の勝負になることもあるので、この方法は頭の片隅に置いておくと良いかと思います。 以上、アセンブラを確認しながらC言語ソースコードを最適化する例でした！\nNote\n簡単にアセンブラを確認する方法を 超便利！C言語のアセンブラ出力を即確認できるサイト｜compiler-explorerに書きました！あわせてご参照ください！\n","permalink":"https://nagayasu-shinya.github.io/posts/assembly-optimization-gcc/","summary":"\u003cp\u003eC言語のループ処理を3種類の書き方でアセンブラに変換し、どの書き方が効率の良い機械語を生成するか比較します。\u003c/p\u003e","title":"C言語のコードをアセンブラ出力を確認しながら最適化する"},{"content":"ユーザーの待ち時間に表示するようなプログレスバーをC言語で表示する方法を説明します。\nソースコードと実行例 先日、C言語でASCII文字がくるくる回るスピナーの作り方を投稿しました c言語で待ち時間を示すスピナーの簡単な表示法｜キャリッジリターン\n今回はプログレスバーを表示する方法を示します。 コード例は下記のようになります。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; int main(int argc, char *argv[]) { unsigned int i, j; for (i = 1; i \u0026lt;= 10; i++) { (void) sleep(1); printf(\u0026#34;\\033[2K\u0026#34;); putchar(\u0026#39;[\u0026#39;); for (j = 0; j \u0026lt; i; j++) putchar(\u0026#39;#\u0026#39;); for (; j \u0026lt; 10; j++) putchar(\u0026#39; \u0026#39;); putchar(\u0026#39;]\u0026#39;); puts(\u0026#34;\u0026#34;); printf(\u0026#34;\\033[2K\\033[G %d sec\\n\u0026#34;, i); printf(\u0026#34;\\033[2F\u0026#34;); fflush(stdout); /* バッファを強制的に出力 */ } puts(\u0026#34;\u0026#34;); /* 改行表示 */ return 0; } 実行結果はこんな感じです。1秒ごとにバーが伸びていき10秒たつと終了します。シンプルなプログレスバーですね。\nコードの解説 特に難しいコードではないですが、要点は printf(\u0026quot;\\033[ ですね。 これは ANSI エスケープコード といいます。 これを使うと文字に色をつけたりカーソルの位置を変更したりもできます。 ANSIエスケープコードについては碧色工房 - ANSIエスケープコードにわかりやすい詳細説明がされていました。 今回の例では下記の３つを使用しました。\nprintf(\u0026quot;\\033[2K\u0026quot;) その行を削除 printf(\u0026quot;\\033[G\u0026quot;) カーソルを行頭に移動 printf(\u0026quot;\\033[2F\u0026quot;) カーソルを2行上に移動 これらの他にもいろいろあります。その気になればいろんなアニメーションが作れます。ちょっとしたCUIでのインタラクティブなプログラムも作れますね。いろいろ遊んでみてください！\nまとめ 今回はC言語で、ANSIエスケープコードを使ってプログレスバーを書きました。 ANSI エスケープコードを使えば可能性は無限大です！ぜひチャレンジしてみてください！\nNote\n今回の投稿は今川館 - ANSIエスケープコードを使ってコンソールアニメーションを 参考にさせていただきました。Go言語でスピナーなどを書く説明をされています。\n","permalink":"https://nagayasu-shinya.github.io/posts/terminal-progress-bar/","summary":"\u003cp\u003eユーザーの待ち時間に表示するようなプログレスバーをC言語で表示する方法を説明します。\u003c/p\u003e","title":"c言語でプログレスバーを表示する｜ASCIIエスケープコード"},{"content":"C言語で、くるくる回るスピナーを表示するかんたんな方法を説明します。\nBash scriptでのスピナー 先日、bash script で待ち時間を示すスピナーの表示にてBashのシェルスクリプトでスピナーを表示する方法を示しました。 スピナーとは、ざっくりいうと待ち時間を示すためのアニメーションですね。 下記の例ではアスキー文字- / \\| \\\\ の４つを使って、風車のようにクルクル回るスクリプトを書きました。 今回は、それをC言語で実装してみます。\nC言語での実装 100秒間のループ中にスピナーを表示するコードを示します。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; int main(void) { const int spinner_c[] = {\u0026#39;/\u0026#39;, \u0026#39;-\u0026#39;, \u0026#39;\\\\\u0026#39;, \u0026#39;|\u0026#39;}; const int spinner_len = sizeof(spinner_c) / sizeof(spinner_c[0]); unsigned int i; for (i = 0; i \u0026lt; 100; i++) { (void) sleep(1); printf(\u0026#34;\\r%c\u0026#34;, spinner_c[i % spinner_len]); fflush(stdout); // バッファを強制的に出力. } puts(\u0026#34;\u0026#34;); // 改行表示. return 0; } コード解説 配列 spinner_cは風車アニメーションのための部品です。 これらを1秒間隔で順番に表示していくことで風車のようなアニメーションを表示します。ちなみにバックスラッシュが２つ連続していますが、これは１つ目のバックラッシュはエスケープ文字です。 例えば改行は\\nと書きますね、あれと同じです。バックスラッシュ自体は２つ連続させる必要があります。 spinner_lenは、配列の要素数です。配列の要素数を計算するための定石ですね。 sizeof(配列名) / sizeof(配列名[0]) とします。この書き方なら配列がint型でもchar型でもなんでも同じように要素数を計算できます。\n次はprintfの中身です。まず、%cとspinner_c[i % spinner_len]についてです。 %cは1文字出力するという意味ですね。 spinner_c[i % spinner_len]の添え字は、インクリメンタルループカウンタのiを配列の要素数で割った余りです。 つまりiが 0 1 2 3 4 5 \u0026hellip; と増加していくとi % spinner_lenは 0 1 2 3 0 1 2\u0026hellip; と0から3の間をループします。\nさて、このコードで一番大事なのは\\rです。これはキャリッジリターンで、「行の先頭へ移動する」という意味です。 Emacs なら C-aですね。これがあるおかげでスピナーのアニメーションを表示できています。 仮にこのキャリッジリターンがなかった場合、アニメーションせずに単に /-\\|/-\\|/-\\|/-\\|/-\\|のように横にずらずらと表示されていきます。 エディタでもそうですよね、普通に入力するとこのように横につながって表示されますよね。 そこでこのキャリッジリターンの出番です。これは行の先頭へ移動する、という意味でした。 EmacsでいうならC-aと同じようなものです。つまり、ここのfor文では、先頭へ戻って1文字出力、先頭へ戻って1文字出力、を繰り返します。 printfの出力はエディタの上書きモードと同じですので、ひたすら先頭行にspinner_cの要素が上書きされます。これがアニメーションとなります。\nまとめ 今回は、キャリッジリターン（\\r）を使えば、C言語でもスピナーを簡単にかけるという例でした！同じようにしてプログレスバーなんかも表示できますね。\n","permalink":"https://nagayasu-shinya.github.io/posts/terminal-spinner-animation/","summary":"\u003cp\u003eC言語で、くるくる回るスピナーを表示するかんたんな方法を説明します。\u003c/p\u003e","title":"c言語で待ち時間を示すスピナーの簡単な表示法｜キャリッジリターン"},{"content":"シェルスクリプトでスピナー（待ち時間中を示すアニメーション）を表示する方法について説明します。\nスピナーとは？ ある程度長い時間（数秒以上）かかる処理を実行したとき、「処理中ですよ」ということを示す風車のようなくるくる回るアイコンを見たことはありますか？ 待ち時間にくるくる回って処理中だと示すやつを「スピナー（spinner）」と言います。 環境によっては砂時計のアイコンだったりもしますね。 スピナーの例としては CSSPINが参考になりますね。\nこのスピナーですが、シェルスクリプトでも実現可能です。 ときどき見かけますね、- \\ | / を順番に表示してくるくる回るアニメーションを表示するやつです。\nスピナーをbash scriptで実装する シェルスクリプトを実行して、数秒間以上何も表示が出てこないと、普通は不安になります。 実は何かの処理中でも、ユーザは不安になってうっかりCtl-ｃで中断したりしちゃいます。それを防ぐために、ユーザに「今頑張って処理してるから！」と示すためにスピナーを使います。 このスピナーをbashのスクリプトでの作り方を示します。 下記のようにechoとsleepを組み合わせればOKです。 このようにアスキーアートでくるくる回るアニメーションを作って、ユーザに「処理中です！」と示すと良いです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/bash chars=\u0026#34;/-\\|\u0026#34; while :; do for (( i=0; i\u0026lt;${#chars}; i++ )); do sleep 1 echo -en \u0026#34;${chars:$i:1}\u0026#34; \u0026#34;\\r\u0026#34; done done # refs. # http://askubuntu.com/questions/623933/how-to-create-a-rotation-animation-using-shell-script まとめ 1秒スリープしたのちアニメーションを更新する、を繰り返すスクリプトを例示しました。 数秒単位で処理時間がかかるスクリプトを作る際に、ユーザに処理中だと示すために便利なスクリプトかなと思います。 これをベースにすればいろいろ応用ができるかなと思います。 GUIを使うまでもなくアスキーアートで風車的なものは表示できますので、いろいろと活用して見ていただければなと思います。\n","permalink":"https://nagayasu-shinya.github.io/posts/bash-shell-spinner-animation/","summary":"\u003cp\u003eシェルスクリプトでスピナー（待ち時間中を示すアニメーション）を表示する方法について説明します。\u003c/p\u003e","title":"bash script で待ち時間を示すスピナーの表示"},{"content":"Windows環境にてEMACS TRAMP がやたらと重くなる場合の解決法について説明します。\n以前に、Emacs Tramp について下記の記事を公開しました。 Emacs Tramp でリモート上のファイルを直接編集する方法｜Windowsにも対応 このWindows環境で使っていて、リモートのファイル編集中にやたらに重くなることが頻発したので、その原因と解決方法を調べました。もし同じ問題で悩んでいる方、参考にしてみてください。 解決法の他に、参考情報としてオートセーブについての簡単な説明と、Tramp の lisp コードのリーディングを載せています。ご参考までに。\n動作が重くなるときに起きていること Windows環境で Tramp モードを使っていて、ときどきやたらに動作が重くなることがありました。 *Message バッファを確認してみると下記のエラーが出ていました。\n1 2 3 Auto-saving... Auto-saving hoge.txt: Opening output file: Invalid argument, c:/Users/username/AppData/Local/Temp/#!plink:user_name@hostname:!home!user_name!hoge.txt# ……オートセーブでこけていました。 ファイル名に:があるのがダメです。GNU/Linuxでは:があっても大丈夫ですが、Windowsはファイル名に:を使えません。\n解決法 さまざまな解決法がありそうですが、ここでは簡単にできる２つの方法を示します。\nオートセーブを無効化してしまう えいやっとオートセーブを無効にしてしまうことで回避可能です。 emacs初期化ファイル（.emacs, .emacs.d/init.el）に下記の1行を追加するだけです。これでオートセーブが無効化されます。 「オートセーブなんか使ったことねえぜ！」という方はこれが一番お手軽かなと思います。\n1 (setq auto-save-default nil) Tramp モード時のみ有効なオートセーブファイルの作成場所を明示的に指定する もう少しスマートな方法が tramp-auto-save-directory変数を設定する方法です。 変数名の通り、Trampモード時のみオートセーブファイルの場所を指定するものです。 これを指定すると、trampがいい感じにオートセーブファイルの名前を変更してくれるようになります。これで問題が解決されます。\n1 (setq tramp-auto-save-directory temporary-file-directory) 【参考】そもそもオートセーブとは？ Emacs にはオートセーブという機能があります。 編集中のファイルを自動で保存する機能です。このオートセーブファイルは編集中のファイルと同じディレクトリに作られます。 例えば/home/user_name/hoge.txt を編集しているときは /home/user_name/#hoge.txt#というファイル名で自動で作成されます。 （デフォルトでは、ファイル内容を変更して「30秒経過」もしくは「300回タイプ」すれば作成されます）\nファイルを編集後にセーブすれば、勝手にオートセーブファイルは削除されます。 このオートセーブファイルですが、編集中のファイルと同じ場所に作成されると散らばってうっとしいので、下記のように特定のディレクトリにまとめるような設定をよくします。\n1 2 3 ;; オートセーブファイルの作成場所をシステムの Temp ディレクトリに変更する. (setq auto-save-file-name-transforms `((\u0026#34;.*\u0026#34; ,temporary-file-directory t))) temporary-file-directory はシステムのテンポラリディレクトリです。Windows7 ですと c:/Users/username/AppData/Local/Temp/ です（隠しフォルダ設定されているかもしれません）。\n【参考】頑張ってどこで問題が起こっているのかlispをみてみる 問題は、オートセーブファイル名に:があることです。よくみると、/は!に変更してくれています。 きっとどこかにファイル名を変更する処理があるはずです。そこに:を``に変更する処理を追加すればいけそうです。\n1 c:/Users/username/AppData/Local/Temp/#!plink:user_name@hostname:!home!user_name!hoge.txt# ということで、Tramp の Lisp コードを眺めてみます。 Emacs をC:/Programs/emacs/ にインストールした場合は下記の場所にあります。 C:/Programs/emacs/share/emacs/25.1/lisp/net/tramp.el.gz\n.gzで固められていますので、msys2などで解凍しましょう。\n1 gzip.exe -d tramp.el.gz すると tramp.el が取得できます。 その中をガンバって読んでいくと、下記のコードが見つかります。 auto savingがどうのこうのとコメントがありますね。 if (null tramp-auto-save-directory)だとbuffer-file-nameをそのママ使い、null でない場合は\\_ / : | [ ]の文字をを置換するようです。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 (setq tramp-auto-save-directory temporary-file-directory) ;;; Auto saving to a special directory: (defvar auto-save-file-name-transforms) (defun tramp-handle-make-auto-save-file-name () \u0026#34;Like `make-auto-save-file-name\u0026#39; for Tramp files. Returns a file name in `tramp-auto-save-directory\u0026#39; for autosaving this file, if that variable is non-nil.\u0026#34; (when (stringp tramp-auto-save-directory) (setq tramp-auto-save-directory (expand-file-name tramp-auto-save-directory))) ;; Create directory. (unless (or (null tramp-auto-save-directory) (file-exists-p tramp-auto-save-directory)) (make-directory tramp-auto-save-directory t)) (let ((system-type \u0026#39;not-windows) (auto-save-file-name-transforms (if (and (null tramp-auto-save-directory) (boundp \u0026#39;auto-save-file-name-transforms)) (symbol-value \u0026#39;auto-save-file-name-transforms))) (buffer-file-name (if (null tramp-auto-save-directory) ;; ☆ ココで置換するかどうか判定！ buffer-file-name (expand-file-name (tramp-subst-strs-in-string ;; ☆ 置換処理！ \u0026#39;((\u0026#34;_\u0026#34; . \u0026#34;|\u0026#34;) (\u0026#34;/\u0026#34; . \u0026#34;_a\u0026#34;) (\u0026#34;:\u0026#34; . \u0026#34;_b\u0026#34;) (\u0026#34;|\u0026#34; . \u0026#34;__\u0026#34;) (\u0026#34;[\u0026#34; . \u0026#34;_l\u0026#34;) (\u0026#34;]\u0026#34; . \u0026#34;_r\u0026#34;)) (buffer-file-name)) tramp-auto-save-directory)))) ;; Run plain `make-auto-save-file-name\u0026#39;. There might be an advice when ;; it is not a magic file name operation (since Emacs 22). ;; We must deactivate it temporarily. (if (not (ad-is-active \u0026#39;make-auto-save-file-name)) (tramp-run-real-handler \u0026#39;make-auto-save-file-name nil) ;; else (ad-deactivate \u0026#39;make-auto-save-file-name) (prog1 (tramp-run-real-handler \u0026#39;make-auto-save-file-name nil) (ad-activate \u0026#39;make-auto-save-file-name))))) ここまでくれは、 tramp-auto-save-directoryでググってみれば、何かしら情報を得られるはずです。\n例えば5.18 Auto-save and Backup configurationがヒットします。 そこに\nset the variable tramp-auto-save-directory to direct all auto saves to that location.\nと記載がありました。わざわざtramp.elを変更する必要はなさそうですね。\nまとめ この記事では、 Windows で Tramp を使うときにオートセーブで動作が重くなるときの解決法を書きました。 特に難しい設定は必要なく、init.el に１つ設定を追加すればいいだけです。 ついでに、オートセーブの簡単な説明とtrampのlispコードも見てみました。 Windows で Emacs Tramp を使っているときに動作が重くなるという方、ご参考ください！\nNote\n@shima_tetsuo さんに教えていただきました！ありがとうございます！ https://twitter.com/shima_tetsuo/status/811806650432487424\n","permalink":"https://nagayasu-shinya.github.io/posts/emacs-remote-autosave-windows-fix/","summary":"\u003cp\u003eWindows環境にてEMACS TRAMP がやたらと重くなる場合の解決法について説明します。\u003c/p\u003e","title":"Windows ＆ Emacs Tramp でオートセーブに失敗するときの対処法"},{"content":"C言語規約シリーズです。今回は標準ライブラリについてです。\nこの記事では標準ライブラリを使うさいに注意すべきことを記載します。 標準ライブラリ関数で実現できることは標準ライブラリ関数を使用してください。 特にメモリ操作系、文字列操作系の関数をわざわざ自作していることがよくあります。 例えばmemcpy memcmp strstrなどです。 メモリ操作や文字列操作にて自作関数を作ろうと思い立ったときは、一歩たちどまって標準ライブラリの一覧を見てみてください。すでにそこにほしい関数があるかもしれません。 逆にロケール設定に依存するマルチバイト系の関数や時間系の関数は使用しないでください。たいてい意図通りにはうごきません。\nsetjmp, longjmpは使用しない 標準ライブラリ関数 setjmp, longjmp関数はマルチタスク環境下では正常に動作しないので利用しないでください。\ntime.hは使用しない 標準ライブラリのtime.hの関数は、実装依存が多く期待通りに動作しないので使用しないでください。\nスレッドアンセーフな標準ライブラリ関数は使用しない マルチタスク環境下では、スレッドアンセーフな関数は正常に動作しません。 下記の関数は、標準ライブラリ関数を含むPOSIXの、スレッドアンセーフな関数です。使用しないでください。\n同等のスレッドセーフな代用関数が用意されている場合がありますので、それを使ってください。 (ex. strtok_r, rand_r, etc\u0026hellip;)\nPOSIXのスレッドアンセーフ関数一覧 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 asctime basename catgets crypt ctime dbm_clearerr dbm_close dbm_delete dbm_error dbm_fetch dbm_firstkey dbm_nextkey dbm_open dbm_store dirname dlerror drand48 ecvt encrypt endgrent endpwent endutxent fcvt ftw gcvt getc_unlocked getchar_unlocked getdate getenv getgrent getgrgid getgrgid getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getopt getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getutxent getutxid getutxline gmtime hcreate hdestroy hsearch inet_ntoa l64a lgamma lgammaf lgammal localeconv localtime lrand48 mrand48 nftw nl_langinfo ptsname putc_unlocked putchar_unlocked putenv pututxline rand readdir setenv setgrent setkey setpwent setutxent strerror strtok ttyname unsetenv wcstombs wctomb (出力用の引数にNULLを渡すとスレッドアンセーフな関数)\n1 ctermid tmpnam wcrtomb wcsrtombs 以上、組み込み環境での標準ライブラリのコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-stdlib-safe-practices/","summary":"\u003cp\u003eC言語規約シリーズです。今回は標準ライブラリについてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜標準ライブラリ"},{"content":"C言語規約シリーズです。今回はポインタの注意すべき点についてです。\nヌルポインタの表現には0でなく\u0026quot;NULL\u0026quot;を使用する コンパイラは、値が0のポインタを「ヌルポインタ」と解釈するので、通常は、定数0とNULLとを区別しなくても問題無く動作します。 ですが、コンパイラがポインタ型なのか整数型なのか判断できないときは、正常に動作しない可能性があります。特に可変引数関数の場合、コンパイラが型チェックをできないので注意が必要です。 表現上もまぎらわしいので、ヌルポインタには0でなくNULLを使用してください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 // 可変引数関数. // 最後の引数は番兵としてヌルポインタを渡す仕様とする. void va_list_func(char *string, ... ); void func_NG(void) { // NG. 最後の番兵のヌルポインタを0で渡しているので、 // 正常に動作しない可能性がある va_list_func(\u0026#34;Hello,\u0026#34;, \u0026#34;world.\\n\u0026#34;, 0); } 適合コード 1 2 3 4 5 6 7 8 9 10 11 // 可変引数関数. // 最後の引数は番兵としてヌルポインタを渡す仕様とする. void va_list_func(char *string, ... ); void func_OK(void) { // OK. NULLで渡しているので、コンパイラもポインタだと理解できる。 va_list_func(\u0026#34;Hello,\u0026#34;, \u0026#34;world.\\n\u0026#34;, NULL); } ポインタはNULLでないことを確認してから参照する NULLポインタへのアクセスはしないでください。 どこを向いているかわからないポインタにアクセスするときは、必ずNULLでないか確認してください。（特に関数の引数でポインタをもらう場合。）\n違反コード 1 2 3 4 void func_NG(int *p) { *p = 0xff; // pがNULLを指しているかもしれない. } 適合コード 1 2 3 4 5 6 void func_OK(int *p) { if (p != NULL) *p = 0xff; } ポインタをより小さい型へのポインタへキャストしない 異なるサイズの型には異なるアラインメントが適用される可能性があります。 例えば処理系によっては、int型(4Byte)は4Byteアラインメントされ、char型(1Byte)は1Byteアラインメントされます。 このとき、奇数バイトに配置されたchar型へのポインタ変数をlong型へのポインタ変数にキャストすると、long型は4Byteにアラインメントされている必要があるため正しくアクセスできません。大きい型へのポインタを小さい型へのポインタにキャストしないでください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 // longへのポインタ型を引数とする関数. void func_fuga(long *long_table); void func_NG(void) { char char_hoge[DATA_LENGTH]; // NG. もしchar_hogeが奇数バイトに置かれていた場合、正常に動作しない。 func_fuga((long *) char_hoge); return; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 // longへのポインタ型を引数とする関数. void func_fuga(long *long_table); void func_OK(void) { long long_hoge[DATA_LENGTH / sizeof(long)]; // OK. func_fuga(long_hoge); return; } 関数のアドレスを取得するときはアドレス演算子\u0026quot;\u0026amp;\u0026ldquo;をつける 関数のアドレスを取得するときは、括弧をつけずに単に関数名を書けば取得できます。 しかしそれだと関数コールの記述ミスなのかどうかがわかりづらいので、関数のアドレスを取得するときも通常の変数と同じように\u0026amp;をつけてください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include \u0026lt;string.h\u0026gt; // 関数ポインタ変数. char* (*func_ptr)(char *buf1, const char *buf2); void func_NG(void) { // NG, strcpyのコールミスなのか、strcpyのアドレスを取得しているのかわかりにくい. func_ptr = strcpy; // NG, func_ptrという関数自体をコールしているのか, // func_ptrというポインタ変数を介して関数コールしているのかわかりにくい. func_ptr(s1, s2); } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 // 関数ポインタ変数. int (*func_ptr)(void); void func_OK(void) { // OK, strcpyのアドレスを取得しているのが明示的にわかる. func_ptr = \u0026amp;callback_func; // OK, func_ptrというポインタ変数を介して関数コールしているのが明確. (*func_ptr)(); } 以上、ポインタについてのコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-pointer-null-handling/","summary":"\u003cp\u003eC言語規約シリーズです。今回はポインタの注意すべき点についてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜ポインタ"},{"content":"C言語規約シリーズです。今回は演算と式についてです。\n一般的に「キャスト」「浮動小数点」「シフト」によくバグが入り込みます。 キャストせずしないですむように、設計時にデータ型を慎重に選択してください。\nまた特に理由がなければcharやshortでなくintを使ってください。intは「計算機にとって自然な型」ですので一般的に高速です。\n例えばループカウンタでintでなくcharやshortを使っているのをときどき見かけますが、実はむしろサイズが大きくなり、かつ、処理速度は遅くなることがほとんどです。 整数の変数には特に理由がない限りintを使用してください。（配列や構造体は除く。）\n浮動小数点式は等号\u0026quot;==\u0026quot;, 不等号\u0026quot;!=\u0026ldquo;での比較をしない 浮動小数点は誤差を含んでいるので、等号・不等号での比較では予期せぬ動作となる恐れがあります。 浮動小数点の比較は、その値が誤差を含めて期待する範囲内かを判断してください。\n違反コード 1 2 3 4 5 6 7 void func_NG(double dValue) { /* 誤差のため dValue が 1.0 ぴったりとは限らない */ if (dValue == 1.0) { // 略. } } 適合コード 1 2 3 4 5 6 7 8 9 #define LIMIT_ERROR 0.001 // 許容誤差の上限値. void func_OK(double dValue) { /* dValueと1.0の誤差がLIMIT_ERROR以下かどうかチェック */ if ((fabs(dValue) -1.0) \u0026lt; LIMIT_ERROR) { // fabs:絶対値を求める関数. // 略. } } volatileやconstをはずすキャストはしない volatileやconstをつけてある場合は、必要があってつけています。 それらを無効にした場合に正常に動作しない可能性があるので、キャストでそれら無効にしないでください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void func_NG_0(void) { volatile int **dbl_ptr; int *ptr; ipp = (int **) \u0026amp;ip; // NG. volatile修飾子をはずしている. } void func_NG_1(void) { const static int cnst_value = 10; (int) cnst_value = 11; // NG. const修飾子を無理やりはずしている. } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void func_OK_0(void) { volatile int **dbl_ptr; volatile int *ptr; ipp = \u0026amp;ip; // OK. } void func_OK_1(void) { static int cnst_value = 10; cnst_value = 11; // OK. } シフト演算子の右辺の項は、0以上でかつ左辺の項のbit幅未満にする シフトされる変数のビット幅より大きくシフトしたときは、どのような値になるかは未定義です。 0になるとは限りません。発見しづらいバグになりますので、変数のビット幅より大きくシフトしないでください。\n違反コード 1 2 3 4 5 6 7 8 void func_NG(void) { unsigned char ucValue; unsigned int uiValue; uiValue = ucValue \u0026lt;\u0026lt; 0; uiValue = ucValue \u0026lt;\u0026lt; 11; // ucValueのビット幅(8)より大きい. } 適合コード 1 2 3 4 5 6 7 8 void func_OK(void) { unsigned char ucValue; unsigned int uiValue; uiValue = ucValue \u0026lt;\u0026lt; 0; uiValue = (unsigned int) ucValue \u0026lt;\u0026lt; 11; // 明示的に32bit幅の unsigned intにキャスト. } int型よりbit幅の小さい型(unsigned char, unsigned short) のデータをbit反転 \u0026quot; ~ \u0026quot; および左シフト\u0026rdquo;\u0026lt;\u0026lt;\u0026ldquo;させるときは、期待する結果の型に明示的にキャストする int型よりbit幅の小さい型は、計算途中でコンパイラに勝手にintへキャストされます（汎整数拡張）。 そのため、intよりbit幅の小さい型でビット反転や左シフトをするときは必ず明示的に元の型にキャストしなおして使ってください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void func_NG(void) { unsigned char uc_port; unsigned char uc_port_inv; uc_port = 0x5a; uc_port_inv = (~uc_port) \u0026gt;\u0026gt; 4; // 0x5aを普通にビット反転すると0xa5なので // それを4bit右シフトすると0x0aが表示されそうだが, // 実際は0xfaが表示される. printf(\u0026#34;uc_inv : 0x%02x\\n\u0026#34;, uc_port_inv); // uc_port_inv = (~uc_port) \u0026gt;\u0026gt; 4; // ----------------------------------- // uc_port ⇒ 0x0000005a (unsigned charからintへの汎整数拡張) // ~uc_port ⇒ 0xffffffa5 // ~uc_port \u0026gt;\u0026gt; 4 ⇒ 0xfffffffa (負数なので符号ビットが右bitへ伝播) // uc_port_inv ⇒ 0xfa } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 void func_OK(void) { unsigned char uc_port; unsigned char uc_port_inv; uc_port = 0x5a; . uc_port_inv = (unsigned char) (~uc_port) \u0026gt;\u0026gt; 4; // 暗黙的な汎整数拡張対策. // 明示的に(unsigend char)とキャストすることにより, // 期待通り0x05が表示される. printf(\u0026#34;uc_inv : 0x%02x\\n\u0026#34;, uc_port_inv); } 構造体や共有体の比較に関数memcmp()を使用しない 構造体のメンバ間には、データのアラインメントの都合により隙間が空くことがあります(パディング)。 そのため、構造体同士をmemcmpで比較すると、各メンバの隙間のゴミ値まで比較してしまい、予期せぬ動作となる恐れがあります。 構造体同士を比較する場合は、それぞれのメンバ同士を比較してください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // member_1とmember_2の間に3Byteのパディング(隙間)がある恐れあり. typedef struct { char member_1; int member_2; } STRCT; void func_NG(void) { STRCT strct_a; STRCT strct_b; strct_a.member_1 = strct_b.member_1 = \u0026#39;z\u0026#39;; strct_a.member_2 = strct_b.member_2 = 0xaa; // 構造体のパディング(隙間)まで比較しているので, // メンバは全部等しくても、memcmpが「等しくない」と返す恐れあり. if (0 == memcmp(strct_a, strct_b)) { ; } } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 typedef { char member_1; int member_2; } STRCT; void func_NG(void) { STRCT strct_a; STRCT strct_b; strct_a.member_1 = strct_b.member_1 = \u0026#39;z\u0026#39;; strct_a.member_2 = strct_b.member_2 = 0xaa; // 個々のメンバに対して、比較を行う. if ((strc_a.member_1 == strct_b.member_1) \u0026amp;\u0026amp; (strc_a.member_2 == strct_b.member_2)) { ; } } 論理演算子(\u0026rdquo;|| \u0026ldquo;,\u0026rdquo;\u0026amp;\u0026amp;\u0026quot;)にはデータを変更する式・関数コール・およびvolatile変数の参照を行う式は用いない 論理演算子は、真偽が確定した時点で実行を中断します。例えば理和||の場合、左の式が真なら右の式は実行されず無視されます。 論理演算子にはデータを変更する式・関数コール・volatile変数の参照を行う式は書かないでください。\n違反コード 1 2 3 4 5 6 7 8 void func_NG(unsigned char ucHoge) { int a = 10; int b = 5; if ((a == 10) || (b++ == 6)) // a == 10の時点で真ということが確定するので、b++ は実行されない. ; // b == 5 のまま. } 適合コード 1 2 3 4 5 6 7 8 9 10 void func_NG(unsigned char ucHoge) { int a = 10; int b = 5; b++; // if文の外でインクリメントする. if ((a == 10) || (b == 6)) ; // b == 6 となる. } ループカウンタに浮動小数点は使用しない 浮動小数点は誤差があるので、ループカウンタには使用しないでください。例えば.1は2進数では表現できない（循環小数）ので、誤差が含まれます。ちなみに、ループカウンタにはint型を推奨します。一般的にchar型、short型を使ってもファームサイズは小さくならず、むしろ大きくなる傾向になります。また、速度も遅くなる傾向になります。\n違反コード 1 2 3 4 5 6 7 8 void func_NG(unsigned char ucHoge) { float cnt; for (cnt = 0.1f; cnt \u0026lt;= 1.0f; cnt += 0.1f) { // NG, 0.1は2進では表現できず、期待通りの回数、ループしない可能性あり. } } 適合コード 1 2 3 4 5 6 7 8 void func_OK(unsigned char ucHoge) { int cnt; for (cnt = 1; cnt \u0026lt;= 10; cnt += 1) { // OK. 期待通り10回ループする. } } 符号無し整数(unsigned)と0との大小の比較をしない 符号無し整数は必ず0以上なので、0との大小比較は常に真となるので意味がありません。符号無し整数を0と大小比較しないでください。\n違反コード 1 2 3 4 5 6 7 void func_NG(unsigned char ucHoge) { if (ucHoge \u0026gt;= 0) // 必ず真になる. return 1; else return 0; } 適合コード 1 2 3 4 5 6 7 void func_OK(signed char scHoge) { if (scHoge \u0026gt;= 0) return 1; else return 0; } 常に真、もしくは常に偽の条件文は使用しない 必ず真になるような条件分は無意味なので記述しないでください。コーディングミスなのか他人には判断しづらく、バグにつながります。また、コンパイラにそうのように解釈される記述もしないでください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 int func_NG(void) { int flag; flag = 1; if (flag == 1) // 必ず真.コンパイラがelse節を抹消する可能性大. return 1; else return 0; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 int func_OK(void) { volatile int flag; flag = 1; if (flag == 1) // volatileがあるので必ず真とは限らない. return 1; else return 0; } sizeof演算子には、データを変更する式・関数コール・およびvolatile変数の参照を行う式は用いない sizeof演算子にわたされた式は、実行されません。sizeof演算子にデータを変更する式・関数コール・およびvolatile変数の参照を行う式は渡さないでください\n違反コード 1 2 3 4 5 6 7 8 void func_NG(void) { int i, j; i = 10; j = sizeof(i++); // sizeofではインクリメントは実行されないのでiは10のまま. } 適合コード 1 2 3 4 5 6 7 8 void func_OK(void) { int i, j; i = 10; i++; j = sizeof(i); // iは11になる. } 条件分で真との比較をしない。偽と比較する 条件文(if文など)では 偽：0 真：非0 （1とは限らない） として扱います。 このため、仮に真を1だと仮定して条件文で真と比較すると、期待通りに動作しない可能性があります。 条件文では常に偽と比較するようにしてください。 また、規格上、論理式では真なら必ず1を返しますが、統一性のため、論理式の場合も偽と比較してください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include \u0026lt;ctype.h\u0026gt; #define IS_TRUE 1 int main(void) { int x, y, z; x = isdigit(\u0026#39;5\u0026#39;); if (x == IS_TRUE) { /* isdigit は真なら非0を返すが、1とは限らない。 * なのでここにはこない可能性がある。 */ } else { ; } y = 2; z = 2; if ((y == z) == IS_TRUE) { /* (y == z) は論理式なので、真なら必ず1を返す。 * なのでここに必ず来る。 * だが、真との比較は間違えのもとなのでコーディング規約的にはNG. */ } else { ; } return 0; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include \u0026lt;ctype.h\u0026gt; #define IS_FALSE 0 int main(void) { int x, y, z; x = isdigit(\u0026#39;5\u0026#39;); if (x != IS_FALSE) { /* 期待通りかならずここにくる */ } else { ; } y = 2; z = 2; if ((y == z) != IS_FALSE) { /* 期待通り必ずここにくる */ } else { ; } return 0; } 無限ループにはwhile(1)でなくfor(;;)を使う while(1)でもfor(;;)でも挙動は同じです。ですがwhile(1)の場合は「条件が定数なので常に真」とコンパイラや静的解析ツールが警告を出すことがあるので、無限ループにはfor(;;)を使ってください。\n違反コード 1 2 3 4 5 6 void hoge_task(void) { while(1) { // 略. } } 適合コード 1 2 3 4 5 6 void hoge_task(void) { for(;;) { // 略. } } 除算をするときは0で割らない 数値で0で割ると、未定義の動作になります。ハングするかもしれませんし何も起こらないかもしれません、0が返ってくるかも知れませんし負の値が返ってくるかも知れません。 除算をするときには割る数が0か否かを確認するようにしてください。\n違反コード 1 2 3 4 unsigned int my_div(unsigned int x, unsigned int y) { return x / y; // NG. yが0だった場合未定義の動作になる. } 適合コード 1 2 3 4 5 6 7 unsigned int my_div(unsigned int x, unsigned int y) { if (y == 0) return 0; else return x / y; // OK. 直前でyの値をチェックしているのでyは必ず非0. } 算術演算子の前後にはスペースを入れる スペースは入れても入れなくても同じ、と考えられがちですが実際はそうでない場合もあります。コンパイラの字句解析は、最長一致の原則で行われます。 つまり、複数の候補があった場合、できるだけ字句が長くなうように軸解析していきます。 たとえば、z=x+++y; という式は z = x までは一意に解析できますが、 その次は +　と ++ のどちらとも取りえます。 この場合コンパイラは、より長い ++と判断します。 結果、z = x++ + y; と判断されます （z = x + ++y;でなく）。\nもしz = x++ + y; でなく z = x + ++y;と判断してもらいたい場合は、プログラマが明示的にスペースを入れてあげる必要があります。\nコンパイラに字句の区切りを正しく伝えるために、適切にスペースを使う必要があります。 とくに算術演算子は他の字句の一部として使用されることがあるため注意が必要です。簡単のため、算術演算子を使う場合は無条件で前後にスペースを入れるようにしてください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int func0(int x, int y) { int z; /* * z = x++ + ++y; のつもりだが、実際は * z = x++ ++ +y; と解釈されるのでコンパイルエラーとなる */ z = x+++++y; return z; } int func1(int *px, int *py) { int z; // // 除算の\u0026#34;/\u0026#34;とポインタ演算子の\u0026#34;*\u0026#34;の間にスペースがないので, // コメントの開始の \u0026#34;/*\u0026#34; と判断されるのでコンパイルエラーとなる. // z = *px/*py; return z; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int func(int x, int y) { int z; /* * 明示的に \u0026#34;+\u0026#34; 演算子の前後にスペースを入れたので, * 期待通り z = x++ + ++y; と解釈される */ z = x++ + ++y; return z; } int func1(int *px, int *py) { int z; // 除算の\u0026#34;/\u0026#34; の前後にスペースがあるので、 // 期待通り *px と *py との除算と判断される z = *px / *py; return z; } 以上、演算と式のコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-operator-best-practices/","summary":"\u003cp\u003eC言語規約シリーズです。今回は演算と式についてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜演算と式"},{"content":"C言語規約シリーズです。今回は変数の定義と宣言についてです。\nこの記事では変数の定義と宣言について注意すべきことを記載します。 変数も関数と同様に、「定義」とは実際にメモリ上に配置されることで、「宣言」とはどこかに定義があることを示すだけのものです。 extern宣言しても、メモリ上には配置されません。また、「定義」は各変数に必ず1つしか書けませんが、宣言はいくつあっても（文法上は）かまいません。\n変数を定義するときも関数と同様に、名前空間についての配慮も必要です。 変数の場合は「関数内からだけ見える」「同じ.cファイル内からだけ見える」「どこからでも見える」の3パタンです。 モジュール化の観点からも、また、名前の重複を避けるためにも、名前空間はできるだけ小さくなるように、つまりできるだけ他から見えないようにしてください。 そうしておけば、後の変更するときにも影響範囲が小さくなり、メンテナンスが楽になります。\n_ で始まるオブジェクト(マクロ・関数･変数etc\u0026hellip;)を定義しない C言語の規格上、_ で始まる名前のオブジェクトは使用不可のものが多いです。 _ で始まる名前のオブジェクトは処理系（標準ライブラリ、コンパイラ組込み関数など）が使用すると決められているものがとても多くあります。 細かい規格をおぼえるのは大変ですし、重複した場合に意図しない動作になるため、_ で始まる名前のオブジェクトは使用しないでください。\n違反コード 1 2 3 4 5 6 7 #ifndef _HOGE_H_INCLUDED_ // ← アンダースコア\u0026#34;_\u0026#34;で始まるのでNG. #define _HOGE_H_INCLUDED_ extern int _variable; // ← アンダースコア\u0026#34;_\u0026#34;で始まるのでNG. int _func(void); // ← アンダースコア\u0026#34;_\u0026#34;で始まるのでNG. #endif 適合コード 1 2 3 4 5 6 7 #ifndef HOGE_H_INCLUDED #define HOGE_H_INCLUDED extern int variable; int func(void); #endif ポインタ変数を引数とする関数で、関数内でポインタ先を変更しない場合、constをつける 引数のポインタ変数にconstをつけると、「この関数では引数で受け取ったポインタ変数の先に何も書き込みませんよ」という意思表示になります（書き込もうとしてもコンパイルエラーになる）。 ですので、値を変更されたら困るポインタ変数も、ユーザーが安心して渡せます。逆に言うと、constがなければ怖くてポインタを渡せません。\n例えば、データの比較をする標準ライブラリ関数memcmpですが、比較するデータのアドレスはconstがついています。 よってmemcmpに渡したポインタ先が書き換えられることを心配する必要はありません。\nint memcmp(const void *s1, const void *s2, size_t n);\n違反コード 1 2 3 4 5 6 7 8 9 // コピー元アドレスsrcの参照先は、絶対に変更しないはずなので const をつけるべき. int memory_copy(void *dst, void *src, size_t size) { int i; for (i = 0; i \u0026lt; size; i++) dst[i] = src[i]; return i; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 // コピー元アドレスsrcの参照先は、絶対に変更しないはず。 int memory_copy(void *dst, const void *src, size_t size) { int i; for (i = 0; i \u0026lt; size; i++) dst[i] = src[i]; //万が一下記のように、constポインタに書こうとしてもコンパイラがエラーを出してくれる。 // src[i] = dst[i]; return i; } 構造体を引数として渡さない 構造体を引数として渡すと、スタック上に構造体すべてのメンバがコピーされるので、スタックオーバーフローの原因になります。 また、構造体のメンバが少なくても、CPUレジスタでなくスタックを使って引数を渡すようになるため、関数呼び出しに大きな時間がかかります（コンパイラの最適化が効きづらい）。\n構造体を引数として渡したい場合は、構造体へのポインタ変数を渡すようにしてください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 struct hoge{ int piyo; }; // 構造体をそのまま渡しているので関数呼び出しに時間がかかる. // (CPUレジスタを使わずスタックを使うため) int func_NG(struct hoge arg) { return arg.piyo; } 適合コード 1 2 3 4 5 6 7 8 9 struct hoge{ int piyo; }; int func_OK(struct hoge* arg_p) { return arg_p-\u0026gt;piyo; } 単項演算子 \u0026ldquo;-\u0026ldquo;は符号無しの値には使用しない 符号無しの値は負数を表現できないので、符号 - をつけても意味がありません。符号無しの値に-は使用しないでください。\n違反コード 1 2 3 4 5 void func_NG(void) { unsigned int uiValue; uiValue = -uiValue; } 適合コード 1 2 3 4 5 void func_OK(void) { signed int iValue; iValue = -iValue; } 8進定数および8進拡張表記は使わない 0で始まる定数は8進数と解釈されます。まぎらわしく、また通常、必要もないので使用しないでください。\n違反コード 1 2 3 table[0] = 1234; table[1] = 4567; table[2] = 0089; // 89(10進)でなく73(10進)が格納される 適合コード 1 2 3 table[0] = 1234; table[1] = 4567; table[2] = 89; // 期待通り89(10進)が格納される \u0026ldquo;??\u0026ldquo;で始まる3文字以上の文字の並びは使用しない ?? で始まる文字は3文字表記(trigraph sequence)と認識されます。 3文字表記とは、キーボードによっては入力できない、ある種の文字の代わりとなる3文字列です。 具体的には下記のように変換がなされます。 日本の一般的なキーボードではまず必要の無い機能ですので、使用しないでください。\nトリグラフ（3文字表記）一覧 1 2 3 4 5 6 7 8 9 ??= → # ??) → ] ??\u0026gt; → } ??( → [ ??\u0026#39; → ^ ??! → | ??/ → \\ ??\u0026lt; → { ??- → ~ 違反コード 1 2 3 4 5 6 7 8 9 10 11 12 void func_NG(void) { int a = 10; /* 下記のコードはコメント行末の「??/」が「\\」に変換されるので、 * a++の行までコメントアウトされます。 */ // a の値はなんだろう??/ a++; // ← ここまでコメント行と認識されてしまう. printf(\u0026#34;a : %d\\n\u0026#34;, a); // a : 10と表示される. } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 void func_OK(void) { int a = 10; /* 「??」の間にスペース追加。 */ // a の値はなんだろう? ?/ a++; // 期待通りインクリメントされます. printf(\u0026#34;a : %d\\n\u0026#34;, a); // 期待通り a : 11と表示される. } (signedでもunsignedでもない)単なるchar型は文字データのみに使用し、数値データは格納しない C言語の規格上、文字型は\nchar型 signed char型 unsigned char型 の3種類あります。ここで、単なるchar型が符号付なのか符号なしなのかは、処理系依存です。 例えばARMのコンパイラは、伝統的にデフォルトでcharは符号無しになっています。 （gcc,RVCT, GHSどれもcharは符号無し型でした）\nオーバーフローなどのバグを防ぐため、単なるchar型は文字データのみとします。 数値を格納する場合はsigned char型もしくはunsigned char型を使用してください。\n違反コード 1 2 3 4 5 6 void func_NG(void) { char char_val; char_val = -4; // 処理系によっては負数は使えない } 適合コード 1 2 3 4 5 6 void func_OK(void) { signed char schar_val; schar_val = -4; // どの処理系でもOk. } signed char型、unsigned char型は数値データのみに使用し、文字データは格納しない char型は符号付か符号無か定義されていないので、数値はchar型には代入禁止とします。 また、統一性のためにsigned char型、unsigned char型は数値のみとし、文字データは代入しないこととします。 (signed, unsigned含む）char型は、int型にくらべて処理速度が遅く、しかもキャスト命令が必要になるのでファームサイズも大きくなります。\nさらに、charはCPUが1サイクルでアクセスできないので、アトミックな制御ができず、マルチタスク環境下では発生頻度の極端にひくいバグにつながります。 配列や構造体以外では、基本的にint型を使用してください。\n違反コード 1 2 3 4 5 6 void func_NG(void) { signed char char_val; char_val = \u0026#39;A\u0026#39;; // 動作はするが、文字データを使う場合はchar型とするべき. } 適合コード 1 2 3 4 5 6 void func_OK(void) { char char_val; char_val = \u0026#39;A\u0026#39;; } CPU以外が更新する可能性のあるデータにはvolatileをつける CPU以外が更新するデータ領域には、volatileをつけてください。 言い換えると、「CPUが知らない間に、データが変更される可能性のある領域にはvolatileをつける」です。 該当するのは例えば、レジスタ、DMA領域、(キャッシュコヒーレンシのない)他CPUとの共有メモリなどです（ハードウェアが更新する可能性があるデータです）。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define ASIC_REG (*(uint32_t *) (0xf0000000)) // ASICレジスタ. void func_NG(void) { ASIC_REG = 1UL; if(ASIC_REG == 0){ /* * すぐ上でASIC_REGに1を代入しているので、 * コンパイラが「このif文にはくるはずないよね。」、と * 解釈してここを削除する可能性あり */ } } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define ASIC_REG (*(volatile uint32_t *) (0xf0000000)) // ASICレジスタ. void func_OK(void) { ASIC_REG = 1UL; if(ASIC_REG == 0){ /* * volatileがついているので、 * 「ASIC_REGに1を代入しているけど、私(CPU)の知らない間にいつの間にか0になっているかも」 * とコンパイラが判断するので、このif文を削除することはない。 */ } } 複数のタスク、割込みハンドラがアクセスする可能性のあるグローバル変数・static変数にはvolatileつける 自タスク以外（他タスク、割込みハンドラなど）が更新する可能性のあるデータ領域には、volatileをつけてください。 言い換えると、「自タスクが知らない間に、データが変更される可能性のある領域にはvolatileをつける」です。 複数のタスクからアクセスされるグローバル変数や、割込みハンドラからアクセスされるグローバル変数などが該当します。自動変数はスタックに詰まれるので、該当しません。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static int temp; void task_A(void) { temp = 1; if (temp == 0) { /* * すぐ上でtempに1を代入しているので、 * コンパイラが「このif文にはくるはずないよね。」、と * 解釈してここを削除する可能性あり * 実際は下記の割込みハンドラで0にされることも考慮してほしい。 */ } } void interrupt_handler(void) { temp = 0; // 変数クリア. } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 static volatile int temp; void task_A(void) { temp = 1; if (temp == 0) { /* * volatileがついているので、 * 「tempに1を代入しているけど、task_A の知らない間にいつの間にか0になっているかも」 * とコンパイラが判断するので、このif文を削除することはない。 */ } } void interrupt_handler(void) { temp = 0; // 変数クリア } const変数は宣言時に初期化する const変数は宣言時にしか値を設定できないので、必ず宣言時に値を設定してください。\n違反コード 1 2 3 4 5 int func_NG(void) { static const int value; // 値が不定。そしてもう二度と変更できない. return value } 適合コード 1 2 3 4 5 int func_OK(void) { static const int value = 5; return value } 同一ファイル内で定義された複数の関数からしかアクセスされないグローバル変数はstaticをつける staticをつけないグローバル変数は、他の.cファイルからも参照できます。 もし、同じ名前のグローバル変数が複数あった場合、リンクエラーにならないことが多く、また、リンク順によってどの変数が参照されるかが変わります（ライブラリの場合はエラーにならない、オブジェクトファイルの場合はエラーになる）。 他への影響を少なくするために、他の.cファイルから参照しないグローバル変数にはstaticをつけてください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // == file0.c == // 本当はfile0.cからしかコールしないグローバル変数 int g_variable; // == file1.c == // 他のファイルからも参照するグローバル変数 int g_variable; // == file2.c == extern int g_variable; void func_NGother(void) { // NG, file0.c, file1.cのどちらのg_variableが参照されるかわからない printf(\u0026#34;%d\\n\u0026#34;,g_variable); } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // == file0.c == // 本当はfile0.cからしかコールしないグローバル変数 static int g_variable; // == file1.c == // 他のファイルからも参照するグローバル変数 int g_variable; // == file2.c == extern int g_variable; void func_OK(void) { // OK, file0.cのg_variableはstaticがついているのでfile2.cからは見えない。 // 必ずfile1.cのg_variableが参照される。 printf(\u0026#34;%d\\n\u0026#34;,g_variable); } 文字列リテラルへのポインタは const 修飾子をつける 文字列リテラル(文字列定数)は、C言語の規格上その領域を変更してはいけませんし、また、コンパイラも通常は文字列リテラルをリードオンリー領域へ配置します（つまり const と同じ領域に配置される）。 ですが文字列リテラルの型自体はただのchar型の配列ですので、その領域を変更するようなコードを書いてもコンパイルエラーにはなりません。 そこで文字列リテラルを保護するために、文字列リテラルを参照するポインタ型変数を使う場合にはchar型でなく const char 型をつかってください。\n違反コード 1 2 3 4 5 6 7 char *s; s = \u0026#34;hello world.\u0026#34;; // NG. 文字列リテラルを参照するポインタ変数なのにconst でない. // なので下記のようなコードを書いてもコンパイルエラーにはならない. s[0] = \u0026#39;H\u0026#39;; // どのような挙動を引き起こすかは不定. 適合コード 1 2 3 4 5 6 const char *s; s = \u0026#34;hello world\u0026#34;; // OK. 文字列リテラルを参照するポインタ変数にちゃんとconstがついている. // なので下記のように文字列リテラルを変更するコードがあると、コンパイルエラーになる. s[0] = \u0026#39;H\u0026#39;; 以上、変数の定義と宣言のコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-variable-definition-declaration/","summary":"\u003cp\u003eC言語規約シリーズです。今回は変数の定義と宣言についてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜変数の定義と宣言"},{"content":"C言語規約シリーズです。今回は型の定義についてです。\nこの記事では型の定義について記載します。ここではtypedefにて型を定義するときを想定しています。 構造体、列挙型、ビットフィールドの定義が主に該当します。 typedefは文法上見落としやすい落とし穴が意外に多いので、要注意です。\nビットフィールドに使用する型はsigned intかunsigned intにする(intも不可) C言語の規格上、ビットフィールドに使える型は、int, signed int, unsigned intのどれかです。 また、ビットフィールドの場合はintは符号付か符号無しになるかはコンパイラ依存なので、明示的にsignedもしくはunsignedをつけてください。\n違反コード 1 2 3 4 typedef struct { unsigned long member_a: 2; // 型がlong. int member_b: 2; // 符号(signed or unsigned)の指定がない. } hoge_t; 適合コード 1 2 3 4 typedef struct { unsigned int member_a: 2; signed int member_b: 2; // 符号ありだと明示的に指定. } hoge_t; 1bit幅のビットフィールドの型はunsigned intを使う（signed intは不可） signed int型は最上位1bitが符号をあらわすbitになります。 1bit幅のビットフィールドをsigned intにした場合、その1bitは符号bitになってしまうので、つまり0か-1かしか表現できません。 ですので、0,1を表現するために、1bit幅のビットフィールドの型はunsigned intを使ってください。\n違反コード 1 2 3 typedef struct { signed int member_a: 1; // 0 か -1のどちらかになる。1にはならない. } hoge_t; 適合コード 1 2 3 typedef struct { unsigned int member_a: 1; // 0 か 1のどちらかになる/ } hoge_t; 列挙型のメンバは、int型で表現できる範囲にする c言語規格上、列挙子はint型です。int型より大きいデータ（long long型など）は格納できません。列挙子はint型で収まる範囲にしてください。\n違反コード 1 2 3 4 5 6 typedef enum { member_0 = 0x1UL, member_1 = 0x10UL, // 略 member_2 = 0x100000000ULL, // int型(32bit)に収まらない. } hoge_t; 適合コード 1 2 3 4 5 6 7 typedef enum { member_0 = 0x1UL, member_1 = 0x10UL, // 略 member_2 = 0x10000000UL, } hoge_t; Note\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-typedef-structuring-rules/","summary":"\u003cp\u003eC言語規約シリーズです。今回は型の定義についてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど）"},{"content":"C言語規約シリーズです。今回は関数の定義と宣言についてです。\nこの記事では関数の定義と宣言について注意すべきことを記載します。「定義」とは実際にメモリ上に配置されることです。 「宣言」とはどこかに定義があることを示すだけのものです。例えばプロトタイプ宣言をしても、これは「宣言」なので実際に関数のコードがメモリに配置されるわけではありません。 「どこかにこういう関数があるよ」と言っているだけです。 一方、「関数の定義」を書けば、メモリのどこかに関数が配置されます。 変数の場合も同様です。extern宣言しても、メモリ上には配置されません。\nまた、「定義」は各関数に必ず1つしか書けませんが、宣言はいくつあっても（文法上は）かまいません。 例えばプロトタイプ宣言をいろんなファイルに書き散らしても文法上はOKですが、関数の定義を複数個書く(多重定義)とNGです。 これは、定義は実際にどこかのメモリに配置されるもの、ということを把握していれば理解できます。\n関数を定義するときは名前空間についての配慮も必要です。 関数定義の場合は、「cファイル内だけから見える」「どこからでも見える」の2パタンあります。 モジュール化の観点からも、また、名前の重複を避けるためにも、名前空間はできるだけ小さくなるように、つまりできるだけ他から見えないようにしてください。 そうしておけば、後の変更するときにも影響範囲が小さくなり、メンテナンスが楽になります。\n関数コール時にプロトタイプ宣言を参照する プロトタイプ宣言を参照しないとコンパイラによる引数チェックが行われません。 コンパイル時にバグを見つけ出すために、必ずプロトタイプ宣言を参照してください。 公開されているヘッダファイルをincludeしてプロトタイプ宣言を参照してください、自前で勝手にプロトタイプ宣言を書かないでください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void func_NG_0(void) { char *ptr; int ch; size_t size; // 略 // NG. プロトタイプ宣言を参照していない memset(ptr1, ptr2); } void func_NG_1(void) { char *ptr; int ch; size_t size; // NG. 自前で勝手にプロトタイプ宣言をしてはだめ. void *memset(void *s, int c, size_t n); // 略. memset(ptr1, ptr2); // NG. } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 #include \u0026lt;string.h\u0026gt; // プロトタイプ宣言のあるヘッダをincludeする. void func_OK(void) { char *ptr; int ch; size_t size; // 略 memset(ptr, ch, size); } 可変引数は使わない 可変引数はプロトタイプ宣言の型チェックが行われないため、バグにつながりやすいので使用しないでください(printf系の関数を除く)。 どうしても必要な場合は、可変引数でなく、argc, argv方式を使用してください。 main関数と同様に、argcに配列の要素数、argvに配列のポインタを渡します。\n違反コード 1 2 3 4 5 // 可変引数なのでNG. int func_NG(int *per, ...) { // 略 } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // argcに配列の要素数、argvに配列へのポインタを渡す. // argcを調整することにより、引数の個数を変えられる. // 何番目の要素が何のパラメータなのかは、ヘッダに明記すること. // ex. // #define PARAM_HOGE 0 // #define PARAM_FUGA 1 // #define PARAM_MAX 2 // 最大要素数. int func_OK(int argc, int *argv) { int param_0, param_2; if (argc \u0026gt;= PARAM_MAX) return -1; param_0 = argv[PARAM_HOGE]; param_1 = argv[PARAM_FUGA]; // 略 } 到達しないコードを書かない バグなのかどうかまぎらわしいので、実行されないコードは書かないでください。 また、致命的なエラーの処理などでどうしても到達しないコードを書く必要がある場合には、その到達しないところに \\* NOTREACHED *\\とコメントを入れておいてください。 多くのコンパイラや静的解析ツールはこのコメントがあるとそこまで制御が実行されないことを理解し、警告などを抑止します。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int func_NG(int tmp) { if (tmp) return 0; else return -1; func_b();// ここには絶対こない. } int func_critical_err_handler(void) { // 略 /* 致命的なエラー発生、しかたなくここで無限ループ */ for (;;) ; return 0; // NG. ここには絶対到達しないので、コンパイラが警告を吐く。 } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int func_OK(void) { if (tmp) return 0; else return -1; // func_b();// ここには絶対こない.削除. } int func_critical_err_handler(void) { // 略 /* 致命的なエラー発生、しかたなくここで無限ループ */ for (;;) ; /* NOTREACHED */ // NOTREACHED コメントで、コンパイラ,解析ツールに到達しないコードだとわからせる. } 引数を持たない関数は、明示的に引数をvoidとして宣言する プロトタイプ宣言のコンパイラチェックを有効にするため、引数がない関数はvoidとしてください。\n違反コード 1 2 3 4 int func_NG() { return 0; } 適合コード 1 2 3 4 int func_OK(void) { return 0; } 同一ファイル内で定義された関数からしかアクセスされない関数はstaticをつける staticをつけない関数は、グローバル関数になるので他の.cファイルからもコールできます。 もし、同じ名前のグローバル関数が複数あった場合、リンクエラーにならないことが多く、また、リンク順によってどの関数がコールされるかが変わります。 他への影響を少なくするために、他の.cファイルからもコールしない関数にはstaticをつけてください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // == file0.c == // 本当はfile0.cからしかコールしない関数. void func_tmp(void) { printf(\u0026#34;File 0.\\n\u0026#34;) } // == file1.c == // グローバルな公開関数. void func_tmp(void) { printf(\u0026#34;File 1.\\n\u0026#34;) } // == file2.c == void func_NG(void) { // NG.file0.cのfuncか、file1.cのfuncか, // どちらがコールされるかわからない. func_tmp(); } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // == file0.c == // file0.cからしかコールしない関数なら, // staticをつける. static void func_tmp(void) { printf(\u0026#34;File 0.\\n\u0026#34;) } // == file1.c == // グローバルな公開関数. void func_tmp(void) { printf(\u0026#34;File 1.\\n\u0026#34;) } // == file2.c == void func_OK(void) { // OK.file0.cのfunc_tmpはstaticなので, // file2.cからはみえない. // file1.coのfunc_tmpがコールされる. func_tmp(); } 1つの関数からしかアクセスしない変数は関数内で定義する 関数の外で定義された変数は、他の関数からも参照可能です。 もし同じ名前のグローバル変数があった場合、変数名が重複してしまいます。意図しない重複を避けるために、1つの関数内でしか使用しない変数はその関数内で定義してください。\n違反コード 1 2 3 4 5 6 7 int variable; //func_NGからしか参照しない. void func_NG(void) { // 略 printf(\u0026#34;%d\\n\u0026#34;, variable); } 適合コード 1 2 3 4 5 6 7 void func_OK(void) { int variable; // func_OKからしか参照しない. // 略 printf(\u0026#34;%d\\n\u0026#34;, variable); } 関数定義内では関数宣言をしない 関数定義内での、グローバルな関数以外の宣言はC言語規格上、NGです。 簡単のため、グローバル関数も含めてすべての関数宣言は行わないようにしてください。関数の外（ファイルスコープ）にて関数宣言を行ってください。 C言語の定石として通常、下記のようにします。\n公開用グローバル関数のプロトタイプ宣言は公開ヘッダファイルにかく 内部用グローバル関数のプロトタイプ宣言はプライベートヘッダファイルにかく 内部用static関数は関数定義と同じ.cファイルの先頭にかく とします。 違反コード 1 2 3 4 5 6 7 void func_NG(void) { extern void func_global(void); // 規格上はOkだが、ルール上NG. static void func_satic(void); // 規格上はNG. return; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /** * @file header_OK.h * 公開ヘッダファイル */ #ifndef HEDADER_OK_H_INCLUDED #define HEDADER_OK_H_INCLUDED extern void func_global(void); // 公開グローバル関数の宣言は公開ヘッダで. #endif //HEDADER_OK_H_INCLUDED // hoge.c #include \u0026lt;hoge.h\u0026gt; static func_satic(void); // 静的関数の宣言も、関数の外で行う. void func_OK(void) { return; } ヘッダファイルで変数や関数の定義をしない、参照のみにする 変数や関数の定義が書かれたヘッダファイルを、複数の.cからincludeすると多重定義になります。 また、大抵の場合、この多重定義はコンパイルエラーにならず、発見しにくい不具合につながります。 変数定義や関数定義は.cに書き、そのextern参照だけをヘッダファイルに書いてください。\n違反コード 1 2 3 4 5 6 7 // hoge.h #ifndef HOGE_H_INCLUDED #define HOGE_H_INCLUDED int hoge_array[] = {0, 1, 2, 3, 4, 5}; // NG. 定義は書かない. #endif 適合コード 1 2 3 4 5 6 7 // hoge.h #ifndef HOGE_H_INCLUDED #define HOGE_H_INCLUDED extern int hoge_array[]; //Ok. 参照だけにする。定義は特定の.cファイルに書く. #endif 以上、関数の定義と宣言のコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-function-definition-declaration/","summary":"\u003cp\u003eC言語規約シリーズです。今回は関数の定義と宣言についてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜関数の定義と宣言"},{"content":"C言語規約シリーズです。今回はマクロとプリプロセッサについてです。\nこの記事ではC言語でプリプロセッサを使うときに気をつけるべき項目を記述します。 プリプロセッサはC言語と違う文法を持っているのでバグの温床となりやすいです。 可能な限りプリプロセッサを使わないでください。 通常はプリプロセッサが必要になるのは、定数の defineとヘッダファイルの include くらいです。 関数マクロは inline 関数で置き換えられる場合がほとんどです。\nプリプロセッサの中でも特に条件コンパイルは注意が必要です。 #ifがネストすると 2 のべき乗で組み合わせのパタンが増えるので、単体テストがほぼ不可能になってしまいます。\n各ルールごとにその理由とルール違反のソースコード例＆ルール適合のソースコード例を書いていますので参考にしてください。\nヘッダファイルは多重インクルード防止のマクロを定義する ヘッダファイルの include を考慮しなくてすむように、各ヘッダファイルには多重インクルード防止のマクロを定義してください。 マクロ名はFILENAME_H_INCLUDEDの形式を推奨します。 すくなくとも最初の一文字目 _ は使わないでください。 C言語の規格上、予約語となっていることが多いためです。\n違反コード 1 2 3 4 5 6 7 /** * @file header_NG.h */ // ヘッダ内コードをここに書く. /* endof header_NG.h */ 適合コード 1 2 3 4 5 6 7 8 9 #ifndef HEADER_OK_H_INCLUDED #define HEADER_OK_H_INCLUDED /** * @file header_OK.h */ // ヘッダ内コードをここに書く. #endif プリプロセッサが削除する箇所も、正しく記述する C 言語の規格上、プリプロセッサが読み飛ばす箇所も、文法的に正しく書かなければなりません。 また、文法上正しくないものをコード内に残しておくとバグのもとになります。 プリプロセッサが削除する箇所も正しく記述してください。 不要でしたら思い切って削除してください。バージョン管理システム(Subversion や Git など)を使っていれば、コードを削除してもいつでも元に戻せます。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 void func_NG(void) { #if 0 覚書. flag が 1 なら hoge()をコール、 flag が 0 なら piyo()をコールする。 // ↑↑↑C 言語で無いのでNG. #endif if (flag == 1) fuga(); else piyo(); } 適合コード 1 2 3 4 5 6 7 8 9 10 11 #if 0 /* * 覚書. * flag が 1 なら hoge()をコール、 flag が 0 なら piyo()をコールする。 */ #endif if (flag == 1) fuga(); else piyo(); } #line は使用しない プリプロセッサの#line を使うと行番号、ファイル名を変更できますが、デバッグ情報などの整合取れなくなるので、使用しないでください。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 // test.c void func_NG(void) { #line 100 \u0026#34;test.c\u0026#34; #error エラー。 /* * 100行目でないのに、エラーメッセージに\u0026#34;test.c l.100\u0026#34;といったような * メッセージが出るはず。 */ } 適合コード 1 2 3 4 5 6 7 // test.c void func_OK(void) { //#line 100 \u0026#34;test.c\u0026#34; #error エラー。 // エラーメッセージに、正しく\u0026#34;test.c l.5\u0026#34;といったようなメッセージが出るはず. } 関数マクロは使用しない、代わりに inline を使う 関数マクロは結局のところただの文字列置換なので、c 言語の関数と同じように使うと想定できない挙動をして不具合がおきることがあります。 より安全で同等のパフォーマンスの得られる inline 関数を使用してください。 また、inline関数はマクロ関数と同様に呼出し箇所すべてに埋め込まれますので、ファームウェアサイズを大きくしないためにも数行程度の大きさにしてください。 さらにinline関数はグローバル関数でなく static 関数にしてください。 (staticにしないとコンパイラがインライン展開してくれないことがあります)\n違反コード 1 2 3 4 5 6 7 8 9 10 #define POW(x) ((x) * (x)) void func_NG(void) { int pow_val; int i = 2; pow_val = POW(++i); // pow = (++i) * (++i); と展開され、インクリメントが 2 回行われてしまう. printf(\u0026#34;pow_val = %d¥n\u0026#34;, pow_val); // pow_valの値がどうなるかは未定義. } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // inline関数利用. static inline int pow(int x) { return ((x) * (x)); } void func_OK(void) { int pow_val; int i=2; pow_val= pow(++i); // 期待通りにインクリメントは一回だけ行われる. printf(\u0026#34;pow_val = %d¥n\u0026#34;, pow_val); // pow_val = 9. } マクロ定義は括弧で囲む 演算子の優先度の違いによる不具合を防ぐため、マクロの定義は必ず括弧で囲んでください。 剰余算と加減算、論理積と論理和、ビットAND とビット OR を混ぜて使う場合にとくに問題が起きやすいです。 マクロはネストして定義されることも多く、一見してどのような計算式に展開されるのかわからないため、演算子の優先度によるバグは発見しづらいので特に注意が必要です。\n違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #define CONDITION_A 1 // 条件コンパイルマクロ A. #define CONDITION_B 0 // 条件コンパイルマクロ B. #define CONDITION_C 0 // 条件コンパイルマクロ C. // 条件 A か B のどちらかが有効のときの条件 D も有効になる(つもり). #define CONDITION_D CONDITION_A || CONDITION_B // 全体を括弧で囲んでいない. void func_NG(void) { #if (CONDTION_D \u0026amp;\u0026amp; CONDTION_C) /* CONDITION_C が 0 なので、ここにはこないつもり */ printf(\u0026#34;?? CONDITION_D and CONDTION_C is enable¥n\u0026#34;); #else printf(\u0026#34;!! CONDITION_D and CONDTION_C is disable¥n\u0026#34;); #endif /* * 上記コードは期待に反して、 * \u0026#34;?? CONDITION_D and CONDTION_C is enable¥n\u0026#34; が出力される。 * * 【理由】 * 「#if CONDTION_D \u0026amp;\u0026amp; CONDTION_C」は、 * 「#if CONDITION_A || CONDITION_B \u0026amp;\u0026amp; CONDTION_C」と展開される。 * 演算子の優先度は「||」よりも「\u0026amp;\u0026amp;」のほうが高いので、これは * 「#if CONDITION_A || (CONDITION_B \u0026amp;\u0026amp; CONDTION_C)」と同じ意味になる。 * なので、CONDTION_C が 0 なのにもかかわらず、 * 期待に反して「#if CONDTION_D \u0026amp;\u0026amp; CONDTION_C」は有効(1)になる。 */ } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #define CONDITION_A 1 // 条件コンパイルマクロ A. #define CONDITION_B 0 // 条件コンパイルマクロ B. #define CONDITION_C 0 // 条件コンパイルマクロ C. // 条件 A か B のどちらかが有効のときの条件 D も有効になる #define CONDITION_D (CONDITION_A || CONDITION_B) // 全体を括弧で囲んでいる void func_NG(void) { #if (CONDTION_D \u0026amp;\u0026amp; CONDTION_C) /* CONDITION_C が 0 なので、ここにはこない */ printf(\u0026#34;?? CONDITION_D and CONDTION_C is enable¥n\u0026#34;); #else printf(\u0026#34;!! CONDITION_D and CONDTION_C is disable¥n\u0026#34;); #endif /* * 上記コードは期待どおり、 * \u0026#34;!! CONDITION_D and CONDTION_C is disable¥n\u0026#34; が出力される。 * * 【理由】 * 「#if CONDTION_D \u0026amp;\u0026amp; CONDTION_C」は、 * 「#if (CONDITION_A || CONDITION_B) \u0026amp;\u0026amp; CONDTION_C」と展開される。 * 演算子の優先度は「||」よりも「\u0026amp;\u0026amp;」のほうが高いが、括弧がついているので * 先に「||」のほうが評価される。 * なので、期待どおり「#if CONDTION_D \u0026amp;\u0026amp; CONDTION_C」は * 無効(0)になる。 */ } ダブルスラッシュ形式のコメントの末尾には半角ピリオド「.」をつける Shift_JIS 文字には、2バイト目が0x5cになっているものがあります(「能」「予」「十」など)。 この0x5c ¥ (バックスラッシュ)を表し、これは C言語ではエスケープを意味します。 つまり、その次の文字が無視されてしまいます。 例えばダブルスラッシュ形式コメントの末尾がダメ文字「能」だった場合、コメント終端の改行文字がエスケープされることになります。 結果、その次の行までコメントと認識されます。このような2バイト目が0x5cになっている文字を俗にダメ文字と言います。\n行の末尾がダメ文字にならないようにコメントを書けばいいのですが、ダメ文字をすべて覚えるのは大変です。「能」や「表」などよく使う文字も含まれています。そこで、 「ダブルスラッシュコメントの末尾は半角ピリオドにする」と一律に決めます。これにより必ずコメントの末尾がダメ文字になるのを避けることができます。\nダメ文字一覧 (2Byte 目が 0x5c:バックスラッシュになるもの) 1 2 3 4 5 ― ソ Ы 噂 浬 欺 圭 構 蚕 十 申 曾 箪 貼 能 表 暴 予 禄 兔 喀 媾 彌 拿 杤 歃 濬 畚 秉 綵 臀 藹 觸 軆 鐔 饅 鷭 偆 砡 違反コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* * 引数 a を引数 b で割った値を返す。 * 引数 b が 0 のときは 0 除算になってしまうためエラーとして-1 を返す */ int div_func(int a, int b) { if (b == 0) // b が 0 の場合は 0 除算になるため計算不可能 return -1; /* * 上記の if 文で 0 除算ガードをしているが、 * ダブルスラッシュコメントの末尾がダメ文字の「能」で終わっている。 * このためコメント末尾の改行文字がエスケープされてしまい、結果、 * 次の行の return -1 までコメントアウトされてしまう。 * 具体的には次のように解釈される。 * ダブルスラッシュ行の末尾に 「return -1;」 が来てしまう * * if (b == 0) // b が 0 の場合は 0 除算になるため計算不可能 return -1; * * そのため、b が 0 の場合も意図に反してここに来てしまう。 * 結果、0 除算が発生してハングする。 */ return a / b; } 適合コード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* * 引数 a を引数 b で割った値を返す。 * 引数 b が 0 のときは 0 除算になってしまうためエラーとして-1 を返す */ int div_func(int a, int b) { if (b == 0) // b は 0 の場合は 0 除算になるため計算不可能. return -1; /* * 上記のダブルスラッシュコメントはダメ文字の「能」のあとの「.」を入れている。 * このためダメ文字は改行でなく「.」をエスケープする。 * よって b が 0 のときは期待通り次の行の return -1 を実行する。 * * 結果、期待通り b が 0 の場合はここまでこない。 */ return a / b; } 以上、プリプロセッサとマクロのコーディング規約でした！\nNote\n下記のC言語コーディング規約シリーズも併せてご参照ください\n組込みソフト向けC言語コーディング規約｜関数の定義と宣言 組込みソフト向けC言語コーディング規約｜演算と式 組込みソフト向けC言語コーディング規約｜ポインタ 組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ 組込みソフト向けC言語コーディング規約｜標準ライブラリ 組込みソフト向けC言語コーディング規約｜型の定義（構造体、列挙型、ビットフィールドなど） 組込みソフト向けC言語コーディング規約｜変数の定義と宣言 ","permalink":"https://nagayasu-shinya.github.io/posts/c-preprocessor-macros/","summary":"\u003cp\u003eC言語規約シリーズです。今回はマクロとプリプロセッサについてです。\u003c/p\u003e","title":"組込みソフト向けC言語コーディング規約｜マクロとプリプロセッサ"},{"content":"Windows にて使っているPCが 32bit なのか 64bit なのかを調べるときの落とし穴について説明します。\nよくあるパタン：環境変数 PROCESSOR_ARCHITECTURE Windows では環境変数 PROCESSOR_ARCHITECTUREにより、プロセッサの種類を知ることができます。 環境変数PROCESSOR_ARCHITECTUREは、例えば、32ビットであれば\u0026quot;x86\u0026quot;、64ビットであれば\u0026quot;AMD64\u0026quot;もしくは\u0026quot;IA64\u0026quot;といった値になります。 下記は32bit CPU にてDOS窓で下記のようにPROCESSOR_ARCHITECTURE変数を表示した場合の例です。\n1 2 c:\\\u0026gt;echo %PROCESSOR_ARCHITECTURE% x86 また、 64 bit CPU だとこうなります（IA64と表示されるかも）。\n1 2 c:\\\u0026gt;echo %PROCESSOR_ARCHITECTURE% AMD64 バッチファイル内で分岐させるなら下記のようになりますね。\n1 2 3 4 5 6 7 8 9 @echo off setlocal if \u0026#34;%PROCESSOR_ARCHITECTURE%\u0026#34; EQU \u0026#34;x86\u0026#34; ( echo \u0026#34;32bit\u0026#34; ) if \u0026#34;%PROCESSOR_ARCHITECTURE%\u0026#34; NEQ \u0026#34;x86\u0026#34; ( echo \u0026#34;64bit\u0026#34; ) ここまでは特に問題ないですね、想定通り。\n環境変数を PROCESSOR_ARCHITECTURE をアプリから表示させてみる ここでちょっとした実験をします。面倒な人は軽く読み流してください。 この便利な環境変数 PROCESSOR_ARCHITECTURE ですが、弱点があります。 例えば64bit CPU をお使いで、かつ、下記の Windows 向け Emacsを使っている人は簡単な実験をしてみてください。 scratch バッファで下記のelispを実行してみてください。\n1 (message \u0026#34;PROCESSOR_ARCHITECTURE is %s.\u0026#34; (getenv \u0026#34;PROCESSOR_ARCHITECTURE\u0026#34;)) AMD64 か IA64 が表示されそうなものですが、下記のように x86と表示されるかと思います。\n1 PROCESSOR_ARCHITECTURE is x86. 64bit なのに 32bit と判定されてしまっています。なんてこった。\nWOW64 と PROCESSOR_ARCHITECTURE Emacs 上で、 環境変数 PROCESSOR_ARCHITECTURE が 32bitを示す x86になったのはなぜでしょうか。 それは使っている Emacs が 32bit CPU向けにビルドされているからです。 もちろん32bit向けアプリケーションは64bit 環境ではそのままでは動きません。 そのため Windows では WOW64というエミュレータが 32bitアプリケーションを 64bit CPU上で動かします。 32bit環境をエミュレートするわけですね。ですので、32bitアプリケーションは自分が32bit環境で動いている気になっています。 そのため、上記のように32bitアプリケーション上では環境変数 PROCESSOR_ARCHITECTUREも32bitを示す値を返してしまいます。\n環境変数 PROCESSOR_ARCHITEW6432 を使おう では、32bit アプリケーション上からは実際の CPU が32bitか 64bitか判断できないのでしょうか？ もちろん、判断できます。環境変数PROCESSOR_ARCHITEW6432 を使えば OK です。 この環境変数には WOW64が元のPROCESSOR_ARCHITECTUREを退避してくれています。\n1 (message \u0026#34;PROCESSOR_ARCHITEW6432 is %s.\u0026#34; (getenv \u0026#34;PROCESSOR_ARCHITEW6432\u0026#34;)) 実行結果は下記のようになるはずです。\n1 PROCESSOR_ARCHITEW6432 is AMD64. ちなみに PROCESSOR_ARCHITEW6432 はWOW64のみで有効になりますのでご注意を。 32bit/64bitにてどの環境変数がどのように設定されるかはマイクロソフト社のサイトWOW64 実装の詳細の下の方に書いてあります。\nまとめ この記事では Windows 環境変数で 32bit CPUか 64bitCPU か確実に判断する方法を書きました。 ついついPROCESSOR_ARCHITECTURE だけをみてしまいがちですが、それだけに頼らずPROCESSOR_ARCHITEW6432 も併用するとグッドです。 32bitアプリケーション内でも正しく 32bit/64bit を判断できます。 具体的にどの環境変数が使えるのかは、MicrosoftのWOW64 実装の詳細のサイトを確認してください。 以上、 Windows環境変数で 32bit CPUか 64bit CPU かを判断する方法でした。\n","permalink":"https://nagayasu-shinya.github.io/posts/windows-processor-detection/","summary":"\u003cp\u003eWindows にて使っているPCが 32bit なのか 64bit なのかを調べるときの落とし穴について説明します。\u003c/p\u003e","title":"Windows で 32bit/64bit を確実に判断する｜PROCESSOR_ARCHITECTUREとPROCESSOR_ARCHITEW6432"},{"content":"今回は Emacs の Trampという機能についてです。これを使えば使いなれたローカルのEmacs 環境からリモートのファイルを直接編集できます！\nリモート上のファイルをローカルの Emacs で編集したい リモートで他のマシン上のファイルを編集をするとき、どのようにしていますでしょうか？例えば下記の２つの方法が考えられますね。\nsshでリモートにログインして、そのマシン上で編集する ftp や scp で編集したいファイルをローカルへ落としてきて編集した後、ftp, scp などでリモートマシンへ転送 前者は直接的な方法ですが、例えば Emacsが普段使用してない設定だったりで何かと面倒です。 数行変える程度なら我慢できますが、使い慣れていない設定のEmacs はストレスが溜まります。 C-hでヘルプが出てきたりしたら殺意すらおぼえますね。\nvi ？ nano？ 起動したら最後、終了させることもママなりません。 後者は使いなれたローカルの環境で編集できるというメリットがありますが、いちいちリモートからファイルを落としてきたりアップしたりとするのが面倒です。 うっかりするとそのうちローカルとリモートと、どちらが最新のファイルかわからなくなったりします。\nEmacs Tramp を使おう そこで Emacs の Tramp機能の出番です！使い方は至極簡単です。いつも通りC-x C-fでファイルを開くときに、\n1 /ssh:username@hostname:/path/to/file とするだけです。これでローカルの Emacs上から直接リモートのファイルを編集できます！ もちろんリモートマシンのホスト名のところはIPアドレスでも OK です。\nファイル名のところは ~/hoge.cのようにホームディレクトリからの相対パスも使えます。 また、リモート上のファイルの場所を覚えていない場合、ファイル名を指定せずにディレクトリ名だけ指定すればdired が開きますので、そこからファイルを選択すれば OKです。 例えばユーザ名が tarou ホスト名が remotehost で、ホームディレクトリを diredで開く場合は下記のようにします。\n1 /ssh:tarou@remotehost:~/ 下記のようにすればホームディレクトリ直下のhoge.cが直接開きます。\n1 /ssh:tarou@remotehost:~/hoge.c また、 ssh の config設定がしてあればもっと便利です。たとえば下記のように設定しておいたとします。\n1 2 3 4 5 6 $ cat .ssh/config Host xserver Hostname svNNNNN.xserver.jp User hangstuck Port 10022 IdentityFile ~/.ssh/id_rsa これならいちいち/ssh:hangstuck@svNNNNN.xserver.jp:~/.bashrcとせずとも/ssh:xserver:~/.bashrcでアクセスできます。便利。\nWindows の場合の注意点 ただし Windows 環境の場合は注意が必要です。Windows の場合は ssh ではTrampが動作しません。ここでは２つの方法を紹介します。\nsshx を使う 以前は Windowsでは PuTTY/Plink が一般的でしたが、いまはWindows標準のsshx が使えます。 PuTTY/Plinkインストールするのがめんどくさい、Windowsの機能だけでTrampを使いたいひとはsshxがおすすめです。\nただし制限としてパスワードでのログインができません。 SSH鍵でのログインになります。公式のマニュアルにも 「Note that sshx　does not bypass authentication questions.」と記載があります。\n念のため、鍵の生成の方法を書いておきます。すでに作成済みなら飛ばしてOKです。 サーバ側にて ssh-keygen コマンドで作成します。下記では暗号方式に RSA を指定しています。 途中でパスフレーズを聞かれますがよくわからなければ空のままでも作成できます。 鍵は~/.ssh/ ディレクトリ以下に作られます。 id_rsaが秘密鍵、id_rsa.pubが公開鍵です。\n1 2 3 4 5 6 7 8 9 10 11 12 $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/shinya/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/shinya/.ssh/id_rsa Your public key has been saved in /home/shinya/.ssh/id_rsa.pub The key fingerprint is: （略） $ ls .ssh/ id_rsa id_rsa.pub 公開鍵をauthorized_keysに追加します。これでサーバ側の設定はOKです。\n1 2 cat ~/.ssh/id_rsa.pub \u0026gt;\u0026gt; ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys 次にクライアント側のWindowsの設定です。先程サーバで作成した秘密鍵 id_rsaを C:\\Users\\username\\.ssh\\ に置きます。 usernameのところはご自身のユーザ名に置き換えてください。\n次に ssh-agentエージェントサービスを起動させます。まずサービスの管理画面を開きます。 「スタートメニュー」→「Windows管理ツール」→「サービス」とたどってください。\nすると下記のようなウィンドウが開きます。その中から「OpenSSH Authentication Agent」 を探してください。\n「OpenSSH Authentication Agent」を見つけたらそれを右クリックして「プロパティ」を選択してください。すると下記のウィンドウが開きます。 そこで「全般タブ」の「スタートアップの種類」を「自動」に設定しOKをクリックしてください。\n再度「OpenSSH Authentication Agent」を探して右クリックし「開始」をクリックしてください。下図を参考にしてください。 これでssh-agent エージェントが使えるようになります。\n次に PowerShell を起動してください。そして下記のように ssh-add に秘密鍵を渡してください。 これで鍵でSSHにログインできるようになりました。\n1 2 PS C:\\Users\\username\u0026gt; ssh-add .\\.ssh\\id_rsa Identity added: .\\.ssh\\id_rsa (.\\.ssh\\id_rsa) ここで一度SSHでパスワード無しでログインできるか確認してください。 これをやらないとなぜかTrampがこけます。一度だけ、明示的にssh.exe でログインしておいてください\n1 2 3 PS C:\\Users\\username\u0026gt; ssh.exe username@hostname Last login: Fri Oct 28 00:43:08 2022 from hoge [username:~]$ これで準備は完了です。下記のように sshx でTrampが使えるようになっているはずです。\n1 /sshx:username@hostname:~/ PuTTY/Plink を使う 以前から Windows でよく使われるSSHクライアントといえばPuTTYがあります。 そのコマンドラインインタフェースのPlinkを使えばEmacs Tramp が動作します。 plink はputtyをインストールすれば使えるようになります。 PATHを通しておくのを忘れずに。\n1 /plink:username@hostname:/path/to/file 最初が違うだけですね。あとは ssh のときと同様です。\nssh のポート番号がデフォルトの22でない場合 基本的にこれで事足りるかと思いますが、時々、sshのポートがデフォルトの22でないマシンがあります。 セキュリティ上、あえてデフォルトから変えているわけですね。\n例えば今現在わたしが使っているエックスサーバー（xserver） はポート番号は22でなく10022です。こういう場合、ポート番号を明示的に指定してあげる必要があります。その方法は下記の通りです。\n1 /ssh:username@hostname#port:/path/to/file ホスト名の後にポート番号を書きます。例えばsshのポート番号が10022の場合は下記のようになります。\n1 /ssh:tarou@remotehost#10022:~/ rootでファイルを開きたい場合 普通に一般ユーザでファイルを開く方法は上記に述べた通りです。ですがroot権限でファイルを開きたいときがありますよね？ その場合の方法を下記に書きます。やり方は簡単で、パイプでsudoに渡すだけです。\n1 /ssh:username@hostname|sudo:hostname:/path/to/file まとめ Emacs Trampを使って、ローカルから直接リモート上のファイルを編集する方法をご紹介しました。 ザクッとポイントをまとめると下記の通りです。簡単。\nC-x C-f のときにちょっとだけファイルの指定方法を変えるだけ Windows の場合は ssh でなく sshx か plink を使う sshポート番号がデフォルト22でない場合は「#」でポート番号を指定 root でファイルを開くときはパイプで\\sudo\\する 以上、Emacs Tramp についでした。\nNote\nオートセーブの設定によっては動作が重い場合があるので、その解決法をWindows ＆ Emacs Tramp でオートセーブに失敗するときの対処法に記載しました！\n","permalink":"https://nagayasu-shinya.github.io/posts/emacs-remote-file-editing/","summary":"\u003cp\u003e今回は Emacs の Trampという機能についてです。これを使えば使いなれたローカルのEmacs 環境からリモートのファイルを直接編集できます！\u003c/p\u003e","title":"Emacs Tramp でリモート上のファイルを直接編集する方法｜Windowsにも対応"},{"content":"Emacsを１つの設定ファイルで複数の環境で使うために、 設定をEmacsバージョンや OS、ログインユーザー名によって切り替える方法を紹介します。\nEmacs のバージョンで設定を切り分ける 2016-09-17 にEmacs 25.1がリリースされましたね！早速アップデートした方もいらっしゃるかと思います。 Emacsを新しいバージョンにアップデートしたときに問題になるのが、互換性の問題です。 メンテナンスが追いついていないパッケージがあったり機能の仕様が変わったりすることがあります。 例えば今回のEmacs 25.1では、以前開いたファイルを再度開いたときに元のカーソル位置を復元する機能であるSavePlaceを有効にするための記述方法が変わりました。 詳細はEmacsWiki Save Place に記載があります。\nそこで、Emacsのバージョンで処理を分けます。emacs-major-version emacs-minor-versionを使えばよいです。 例として、下記のようになります。\n1 2 3 4 5 6 ;;; enable saveplace (if (and (\u0026gt;= emacs-major-version 24) (\u0026gt;= emacs-minor-version 5)) ;; For GNU Emacs 24.5 and older versions. (progn (require \u0026#39;saveplace) (setq-default save-place t)) ;; For GNU Emacs 25.1 and newer versions. (save-place-mode 1)) これで、新しいバージョン Emacs 25.1 でも古いバージョンでも、同じ Emacs初期化ファイルで共有させることができます。 ちなみに、今使っているEmacsのバージョンを確認するコマンドは M-x versionです。 エコーエリアに下記のように Emacsの情報が表示されます。\n1 GNU Emacs 24.5.1 (x86_64-apple-darwin13.4.0, NS apple-appkit-1265.21) of 2015-04-11 on builder10-9.porkrind.org OSによって設定を切り替える Emacs は WindowsやLinux、Mac OS X などいろんな OS上で動作します。 そこで複数の OSで設定を切り替える方法を説明します。\nいま使用している OS を表示させてみる｜message 関数と system-type 変数 まずは、いま使用している OS を確認してみます。 message 関数と system-type 変数を使用します。 message 関数はC言語でいう printf と同じようなフォーマット表示関数で、 system-type 変数はOSの情報が格納されています。 下記の elispを評価してみてください。閉じ括弧のところで C-x C-e とします。\n1 (message \u0026#34;OS is %s.\u0026#34; system-type) するとエコーエリアにメッセージが表示されます。OS によって表示されるメッセージが異なります。下記のようになるはずです。\nMac OS X の場合 OS is darwin. Windows OS is windows-nt. Linux OS is gnu/linux. WSL OS is gnu/linux. Linux と WSL は同じになりますね。\nWSL と Linux の判別 上述の通り system-type では Linux と WSLの区別がつきません。 そこでもうひと手間かけます。WSL には WSL_DISTRO_NAME という環境変数にディストリビューションの名前が設定されます。 たとえば Ubuntu-20.04 のように設定されているはずです。 そこで下記のようにWSL_DISTRO_NAME の長さが0かそれより大きいかで判断します。\n1 (when (eq system-type \u0026#39;gnu/linux) (if (= (length (getenv \u0026#34;WSL_DISTRO_NAME\u0026#34;)) 0) (message \u0026#34;OS is Linux\u0026#34;) (message \u0026#34;OS is WSL\u0026#34;))) OS を判定して処理を分岐させる設定ファイル例 これを利用して OSによって処理を分岐させることで、設定ファイルを共有させます。 例として、OS によって PATH設定の切り替えをする例を書きます。 今回はWindows と Mac OS X の例です。Linux でも OS 判定の方法は同様です。\n1 2 3 4 5 6 7 8 9 10 ;; OS によって設定を切り替える例 (when (eq system-type \u0026#39;windows-nt) ; Windows (setenv \u0026#34;PATH\u0026#34; (concat \u0026#34;C:\\\\Programs\\\\msys64\\\\usr\\\\bin;\u0026#34; (getenv \u0026#34;PATH\u0026#34;)))) ; msys2 の PATH 設定を追加 (when (eq system-type \u0026#39;darwin) ; Mac OS X (exec-path-from-shell-initialize)) ; PATH 設定を引き継ぐ (when (eq system-type \u0026#39;gnu/linux) (if (/= (length (getenv \u0026#34;WSL_DISTRO_NAME\u0026#34;)) 0) ; WSL (w32-ime-initialize))) ログインユーザー名で設定を切り替える ログインユーザー名でも切替可能です。 user-login-nameを利用します。\n1 2 3 4 5 6 ;; ログイン名に応じてプロキシの設定を行う. (if (equal (user-login-name) \u0026#34;hoge_user_name\u0026#34;) (setq url-proxy-services \u0026#39;((\u0026#34;http\u0026#34; . \u0026#34;proxy.hoge.co.jp:8080\u0026#34;) (\u0026#34;https\u0026#34; . \u0026#34;proxy.hoge.co.jp:8080\u0026#34;) ))) まとめ 今回は、Emacsバージョン、OS, ユーザー名で設定を切り替える方法を説明しました。 これで複数の環境で設定ファイルをうまく共有できますよ！\n","permalink":"https://nagayasu-shinya.github.io/posts/emacs-compatibility-handling/","summary":"\u003cp\u003eEmacsを１つの設定ファイルで複数の環境で使うために、\n設定をEmacsバージョンや OS、ログインユーザー名によって切り替える方法を紹介します。\u003c/p\u003e","title":"Emacsの設定ファイルを複数の環境で切り替える"},{"content":"C言語にはファイルサイズを取得する標準ライブラリ関数がありません。 いろいろな実装方法がありますがその１つを紹介します。\nC言語にはファイルサイズを取得する標準関数がない C言語には、標準ライブラリにてさまざまなファイル操作関数が提供されています。ですが、ファイルサイズを取得する標準関数はありません。 そのため、ファイルサイズを取得するには自分でコードを実装する必要があります。 一般的に使われているfseek()関数を使った実装で事足りますが、これは厳密にはC言語規格に適合していません。 そこで今回は、POSIXを利用してC言語規格に適合したファイルサイズ取得関数を紹介いたします。\nC言語規格に適合したファイルサイズ取得方法 fstat() 関数を使用した例を示します。Linuxはもちろん、MSYS2＠Windowsでも動作します\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;fcntl.h\u0026gt; #include \u0026lt;sys/stat.h\u0026gt; #include \u0026lt;sys/types.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; #define ERR_PRINTF_EXIT(...) do { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while(0) /** * @brief ファイルサイズ取得. Windows / Linux 両対応, のはず. * @param[in] in_fname ファイル名の文字列 * @retval ファイルサイズ */ static long get_read_file_size(const char *in_fname) { FILE *fp; long file_size; struct stat stbuf; int fd; fd = open(in_fname, O_RDONLY); if (fd == -1) ERR_PRINTF_EXIT(\u0026#34;cant open file : %s.\\n\u0026#34;, in_fname); fp = fdopen(fd, \u0026#34;rb\u0026#34;); if (fp == NULL) ERR_PRINTF_EXIT(\u0026#34;cant open file : %s.\\n\u0026#34;, in_fname); if (fstat(fd, \u0026amp;stbuf) == -1) ERR_PRINTF_EXIT(\u0026#34;cant get file state : %s.\\n\u0026#34;, in_fname); file_size = stbuf.st_size; if (fclose(fp) != 0) ERR_PRINTF_EXIT(\u0026#34;cant close file : %s.\\n\u0026#34;, in_fname); return file_size; } fseek()関数を使っても、まずちゃんと動くのですが、さらにコードの可搬性を求めるなら、今回紹介した実装の方が良いでしょう。 ぜひご活用ください！\nNote\n上記の関数はJCERT CCを参考にしました。\n","permalink":"https://nagayasu-shinya.github.io/posts/c-file-size-posix-fstat/","summary":"\u003cp\u003eC言語にはファイルサイズを取得する標準ライブラリ関数がありません。\nいろいろな実装方法がありますがその１つを紹介します。\u003c/p\u003e","title":"規格違反にならないC言語でのファイルサイズ取得 ｜POSIX  fstat 関数使用"},{"content":"ファームウェア開発をしているとときどきちょっとバイナリファイルを作りたいときがあります。 そのかんたんな方法を説明します。\necho を使って簡単にバイナリファイルを作成する ファームウェア開発をしていると、ちょっとしたバイナリファイルを作りたいときがありますよね。よくある方法は、バイナリエディタで作ったり、ちょっと頑張る人ならC言語でプログラム組んだりしますね。 ただ、ちょっとしたバイナリファイルを作成するだけなら bash なら簡単にできますよ。 あの echo や printf コマンドを使うだけです。オプション -en を使えばOKです！\n例えば、すべてのbitが1の 4Byteのファイルを作る場合は下記のようにすればOKです。 ちなみにxxd -g1 は1Byteづつ表示するコマンドです。\n1 2 3 $ echo -en \u0026#34;\\xff\\xff\\xff\\xff\u0026#34; \u0026gt; hoge.bin $ xxd -g1 hoge.bin 00000000: ff ff ff ff みんな大好き 0xdeadbeef の場合はこんな感じ。もし「0xdeadbeef について何？？」て思った人はこのWikipediaを見てみてくださいね。\n1 2 3 $ echo -en \u0026#34;\\xde\\xad\\xbe\\xef\u0026#34; \u0026gt; fuga.bin $ xxd -g1 fuga.bin 00000000: de ad be ef 最後にもう一つ。ARMっ子ならご存知の、無限ループ命令ですね。\n1 2 3 $ echo -en \u0026#34;\\xea\\xff\\xff\\xfe\u0026#34; \u0026gt; forever_loop.bin $ xxd -g1 forever_loop.bin 00000000: ea ff ff fe printf を使って簡単にバイナリファイルを作成する printfをつかえばさらに柔軟にバイナリを生成できます。まずは先程と同じ 0xdeadbeef を生成する場合。%08x というのは8桁の16進数を表示しろという意味です。\n1 2 3 $ printf \u0026#39;%08x\u0026#39; 0xdeadbeef | xxd -r -p \u0026gt; hoge.bin $ xxd -g1 hoge.bin 00000000: de ad be ef .... %08x を %x とすると、最初が0で始まる値を勝手に0削除してしまうのでNGです。\n1 2 3 4 $ printf \u0026#39;%x\u0026#39; 0x00112233 | xxd -r -p \u0026gt; hoge.bin $ xxd -g1 hoge.bin 00000000: 11 22 33 $ printf なので10進数でも入力できます。\n1 2 3 $printf \u0026#39;%08x\u0026#39; 100000 | xxd -r -p \u0026gt; hoge.bin $ xxd -g1 hoge.bin 00000000: 00 01 86 a0 今度はたとえば100000という10進の値をバイナリにしたいとき。下記のように10進数のまま printf に渡せばOKです。printf のフォーマッターがいい感じにしてくれます。\n1 2 3 $ printf \u0026#39;%08x\u0026#39; 1000000 | xxd -r -p \u0026gt; hoge $ cat hoge |xxd -g1 00000000: 00 0f 42 40 もっと長い値を変換したいときも下記のようにすればOK.\n1 2 3 $ printf \u0026#39;%08x\u0026#39; 0x01234567 0xdeadbeef 100000 | xxd -r -p \u0026gt; hoge.bin $ xxd -g1 hoge.bin 00000000: 01 23 45 67 de ad be ef 00 01 86 a0 .#Eg........ 以上、ちょっとしたバイナリファイルを簡単に作成する方法でした！\n","permalink":"https://nagayasu-shinya.github.io/posts/bash-binary-file-generation/","summary":"\u003cp\u003eファームウェア開発をしているとときどきちょっとバイナリファイルを作りたいときがあります。\nそのかんたんな方法を説明します。\u003c/p\u003e","title":"【簡単】バイナリファイルをコマンド一発で生成｜echoとprintfコマンド"},{"content":"RFC 3676に準拠したメール署名（シグネチャ）の書き方を紹介します。\nみなさま、日々の業務でメール書いていますか。 「コードよりメールの方が書く量が多いわい！」という方もたくさんいらっしゃるかと思います。 今回は、そのメールの署名（シグネチャ）についてです。 送信メールには自動で署名（シグネチャ）をつけるように設定していますよね？ 職場なら、名前と会社名と所属、電話番号やFAX番号、E-mailアドレスを入れますよね。例えばこんな感じでしょうか。\n1 2 3 4 5 6 ♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩ 佐藤　太郎 海山株式会社　営業部 TEL 090-XXXX-XXXX Mail satou-tarou@xxxx.co.jp ♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩ 音符がたくさんあって、なんかごキゲンな署名ですね。営業職の女性なんかはもっとかわいらしい装飾をしますよね。ステキです。 ただ、我々エンジニアたるものは、そのような署名を書いてはなりません。なぜなら、 技術者ならば遵守すべきRFC 3676に署名について言及があるからです！ 技術屋にそんな愛らしさなんて誰も求めていません！\n以下、RFC 3676 の該当部を斜体で引用します。\n1 2 3 4 4.3. Usenet Signature Convention There is a long-standing convention in Usenet news which also commonly appears in Internet mail of using \u0026#34;-- \u0026#34; as the separator line between the body and the signature of a message. ようは署名の開始は-- で始めろ、ということですね。「ハイフン＆ハイフン＆スペース」です。最後のスペースを忘れないように！ これはシグダッシュとかsig-dashesとかと呼ばれます。これに準じて署名を書くと下記のようになりますね。\n1 2 3 4 5 -- 鈴木　次郎 海山株式会社　開発部 TEL 090-XXXX-XXXX Mail satou-tarou@xxxx.co.jp これでまともなメーラーなら、署名のところを薄く表示したり、複数回表示するのを抑止したりと、いろいろ気を利かせてくれます。 別に必須というわけではないんですが、メーラーが署名を認識してくれるとメール本文が見やすく表示されるのでオススメです。 返信の応酬で長くなったメールなんかでは、この形式の署名だととても助かります。 ただ、中にはどうしてもかわいい愛され署名を使いたい人もいるでしょう。そのような方は、下記のようにすればよいでしょう。最初に-- を追加しただけですが。。。\n1 2 3 4 5 6 7 -- ♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩ 佐藤　太郎 海山株式会社　営業部 TEL 090-XXXX-XXXX Mail satou-tarou@xxxx.co.jp ♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩〜♩ ちなみに MS outlook は気が利かないどころか、勝手に-- を --（末尾のスペース無し）に変換します。 まあ、ね。諦めましょう、Outlookな人は。\nということで、ちょっと差がつくメールの署名（シグネチャ）の書き方でした。\n","permalink":"https://nagayasu-shinya.github.io/posts/email-signature-format-rfc/","summary":"\u003cp\u003eRFC 3676に準拠したメール署名（シグネチャ）の書き方を紹介します。\u003c/p\u003e","title":"技術屋っぽいメールの署名の書き方｜sig-dashes"},{"content":"オライリー社のオライリージャパン GNU Make 第3版のPDFの紹介です。\nファームウェアのビルドに欠かせないツールと言えば make ですね。 なんだかんだ言って、make が使えると何かと便利です。現在、市販の make の書籍といえば GNU make 3.81 を対象とした下記のオライリーの本がベストかなと思います。 この本は、もちろん書店で買ってもいいですが、 PDF でなら GNU Free Document Licenseに則り無料で公開されています。 ちょっと場所がわかりづらいのでリンク先を貼っておきますね。オライリージャパンのサイトの中にありますよ。 オライリージャパン GNU Make 第3版 公式マニュアルは英語ですし日本語訳は情報が古い場合がありますので上記の PDFがオススメです。\n","permalink":"https://nagayasu-shinya.github.io/posts/gnu-make-manual-pdf/","summary":"\u003cp\u003eオライリー社の\u003ca href=\"http://www.oreilly.co.jp/library/4873112699/\"\u003eオライリージャパン GNU Make 第3版\u003c/a\u003eのPDFの紹介です。\u003c/p\u003e","title":"GNU Make 第3版 日本語版（オライリー）のPDF版電子書籍（ライセンス：GFDL）"},{"content":"GNU Makeの .SUFFIXES を最適化することで、簡単にビルド時間を数％削減できるニッチな方法を紹介します。\nビルド時間は短ければ短いほどいいのは、エンジニアなら誰しも納得いただけるところと思います。 仮にビルド時間を1分短縮できれば、ビルド回数×開発者人数×単価（円）がそのまま経費削減できます。 大規模プロジェクトだと、これは結構効いてきますよね。開発者自身にとってもビルド待ちは面倒ですし。\nということで、今回は GNU make 環境下でのビルド高速化についてお伝えします。 と言っても、ccacheのように劇的な効果をもたらすツールはメジャーかなと思いますので、今回は、そんなに効果はないけど簡単にかつちょっとだけビルドが速くなる、ニッチなローリスクローリターンな方法をご紹介します。 規模やMakefileの書き方にもよるかと思いますが、運が良ければ数分の作業で数％のビルド時間削減ができるかも、 です。なんにせよほぼデメリットはないのでやって損はないでしょう。 やり方は簡単です。 Makefile の先頭行に下記の1行を追加してください。\n1 MAKEFLAGS += --no-builtin-rules たったこれだけで終わりです。 time コマンドなどで実行時間を計測してみてください。 変わらないか、ほんのわずか速くなっているかと思います。 原理を簡単に説明します。別に知らなくても困らない知識ですので、興味のある人だけ読んでいただければ幸いです。 今回の手法は、暗黙のサフィックスルールを無効化するための記述です。例えば main.o を作れ！と指示されると、make は内部に持っているデータベースのデフォルト値を使って、 main.v main.F などなどを勝手に探し回ります。 下記のようにちゃんとパターンルールを指定していても、なぜか探し回ります。\n1 %.o : %.c そのため、今回ご紹介した方法で暗黙のサフィックスルールを抑止してあげます。 すると、明示的に指定していないような無駄なルールの探索（.vやら .Fやら）をしなくなるので多少高速化が見込めます。 ちなみに、今回の対応を行うとログの行数が下記のように数割に減りますね。\n1 2 3 4 $ make -d 2\u0026gt; /dev/null | wc -c 63670 $ make -d 2\u0026gt; /dev/null | wc -c 1183 デフォルトのままのときのログを一部抜粋します。よくわからない拡張子まで探索に行きますねぇ。\n1 2 3 4 5 6 7 8 9 10 11 12 Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.c\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.cc\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.C\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.cpp\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.p\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.f\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.F\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.m\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.r\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.s\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.S\u0026#39;. Trying pattern rule with stem `makefile\u0026#39;. Rejecting impossible implicit prerequisite `makefile.mod\u0026#39;. 以上です。多少でもお役に立てば。\n","permalink":"https://nagayasu-shinya.github.io/posts/make-suffix-rules-optimization/","summary":"\u003cp\u003eGNU Makeの \u003ccode\u003e.SUFFIXES\u003c/code\u003e を最適化することで、簡単にビルド時間を数％削減できるニッチな方法を紹介します。\u003c/p\u003e","title":"GNU make のビルド高速化｜サフィックスルール"},{"content":"プロフィール 横浜市在住の組み込みソフトウェアエンジニア。\n普段やっていることはブートローダ、デバイスドライバ、RTOS/Linuxカーネル周りの開発です。C/C++とARMアセンブラが中心で、Yocto Linux、Android（AOSP）、μITRONあたりを扱っています。Jenkins・Docker・GitHub Actionsを使ったCI/CDやビルド環境の整備もよくやります。\nLinks GitHub: https://github.com/nagayasu-shinya LinkedIn: https://www.linkedin.com/in/nagayasu-shinya/ Facebook: https://www.facebook.com/nagayasu.shinya ","permalink":"https://nagayasu-shinya.github.io/about/","summary":"\u003ch2 id=\"プロフィール\"\u003eプロフィール\u003c/h2\u003e\n\u003cp\u003e横浜市在住の組み込みソフトウェアエンジニア。\u003c/p\u003e\n\u003cp\u003e普段やっていることはブートローダ、デバイスドライバ、RTOS/Linuxカーネル周りの開発です。C/C++とARMアセンブラが中心で、Yocto Linux、Android（AOSP）、μITRONあたりを扱っています。Jenkins・Docker・GitHub Actionsを使ったCI/CDやビルド環境の整備もよくやります。\u003c/p\u003e","title":"About"}]