(Goで真のクロスプラットフォームコードを記述するためのヒントを含む記事の翻訳)Goは、さまざまなプラットフォームでの作業に最適です。 私の主な開発環境はWindowsですが、常にLinuxシステムを使用しています。 したがって、私は自然に問題を引き起こす可能性のあるものを避けようとします。

クロスプラットフォーム開発に対する私の姿勢は、自分を真面目な開発者と見なす場合は
、少なくとも他のプラットフォームでコードを
ビルドする必要があるということです。他のプラットフォーム上のライブラリ。
最近、ジャーナリングと圧縮に重点を置いた非常に優れたアーカイバである
zpaqの代替案を
検討したかったため、Windowsバージョンの非常に優れた
バックアッププログラムの作成を支援しました。 移植中、私は他の人にとって役に立つかもしれないいくつかのことに注意しました。
syscall(またはsys)の使用を最小限に抑える
明白なことから始めましょう。
syscallパッケージはプラットフォームごとに異なり
ますが、共通点はありますが、問題が発生することはほぼ保証されています。 もちろん、それを使用する非常に良い理由がありますが、それを使用する前に、同じことをする他の方法がないことを確認してください。 syscall / sysを使用する場合は、すぐに、移植に必要なアセンブリタグを使用して個別のファイルを作成する必要があることを準備します。たとえば、// + darwin dragonfly freebsd linux netbsd openbsd solarisをビルドし、他のプラットフォーム。
github.com/golang/sysパッケージもあります。これは、システムコールを各プラットフォームの個別のパッケージに配布します。 ただし、これは問題を解決しないため、ここでも同じ考慮事項が適用されます。
信号に依存しないようにしてください
signalάνοςbyσαλιγόπουλοςによる「信号なし」シグナルは非常に便利です。 SIGHUPを使用して構成を再ロードするサーバー、SIGUSR2を使用してサービスを再起動するサーバーなどが多数あります。 これらの信号は他のプラットフォームでは利用できないため、
主な機能をそれらに依存させないでください。 上記の例のないWebサーバーは、一部の機能がなくてもWindowsで正常に機能します。 もちろん、Windowsに対して同様のソリューションを用意する方が良いでしょうが、サーバーがコンパイルされて正常に動作する限り、誰も気にしないと思います。
したがって、たとえば、特定の機能するサービスを作成する場合、サービスにコマンドを送信する唯一の方法はシグナルにしないでください。
ファイルシステムの違い
ファイルシステムは異なることに注意してください。
- ほとんどのオペレーティングシステムには、大文字と小文字が区別されるファイルシステムがありますが、Windowsはありません。 私のアドバイス:常に小文字を使用する
- os.PathSeparatorを覚えておいてください 。 常に使用しますが、これが唯一の可能な区切り文字ではありません。 Windowsは「/」と「\」の両方を使用できるため、ユーザーから受け取ったパスには両方を含めることができます。
- 常にfilepathパッケージを使用してください。 それはもう少しコードかもしれませんが、あなたと他の人を頭痛から救います。
- os.Removeおよびos.RemoveAllは、Windowsで読み取り専用ファイルを削除できません。 これはバグであり、かなり前に修正されているはずです。 残念ながら、政治。
- os.Link、os.Symlink、os.Chown、os.Lchown、os.Fchownは、Windowsでエラーを返します。 ただし、これらのエラーはWindowsにのみエクスポートされます 。
- バイナリがクロスコンパイルされている場合、 os / user.Currentは機能しません。 ここを見てください 。 ありがとう@njcw
- そして、それらを変更/削除した後は、 常にファイルを閉じてください。
ところで、最後のポイントは、私が出会った最も一般的な間違いです。
func example() (err error) { var f *os.File f, err = os.Create("myfile.txt") if err != nil { return } defer f.Close() err = f.write([]byte{"somedata"}) if err != nil { return }
これはそれほど明白なエラーではありませんが、簡単な例があるため、ファイルを閉じる
前に削除しようとしていることがわかります。
問題は、これがほとんどのシステムでうまく機能することですが、Windowsでは落ちます。 これを行うためのより正しい例は次のとおりです。
func example() (err error) { var f *os.File f, err = os.Create("myfile.txt") if err != nil { return } defer func() { f.Close() err2 := os.Remove("myfile.txt") if err == nil && err2 != nil { err = err2 } }() err = f.write([]byte{"somedata"})
ご覧のとおり、ファイルを閉じる順序を維持することは簡単な作業ではありません。 2つの遅延を使用するアプローチを選択する場合、遅延の呼び出しは逆の順序で実行されるため、閉じる前にos.Removeを定義する必要があることに注意してください。
WindowsとLinuxのファイルシステムの違いを説明
するより詳細な記事があります。
ANSIを使用する場合はトランスレーターを使用します

コンソールコマンドを使用して出力をフォーマットすることは、良い解決策です。 これにより、テキストをスクロールすることなく、色を使用したり進行状況を表示したりすることで、視覚的な認識を容易にすることができます。
ANSIコードを使用する場合は、常にトランスレーターライブラリを使用する必要があります。 すぐに使用して、後で頭痛から自分を救います。 ランダムに見つけたものをいくつか紹介します。
他の良いライブラリを知っているなら、コメントに書いてください。
シンボリックリンクへの依存を回避する
シンボリックリンクは素晴らしいことです。 これにより、新しいバージョンのファイルを作成したり、ファイルの最新バージョンを自動的に指すリンクを作成したりするなど、クールなことができます。 ただし、Windowsでは、プログラムに管理者権限がある場合にのみシンボリックリンクを作成できます。 したがって、これはちょっとしたことですが、プログラムの機能がそれに依存しないことを確認してください。
可能であれば、CGOおよび外部プログラムを避けてください。
Windowsでビルドするための作業環境をセットアップするのは非常に難しいため、できるだけ早くCGOを避けるように努力する必要があります。 cgoを使用すると、WindowsだけでなくAppEngineユーザーも拒否します。 コードがライブラリではなくプログラムである場合は、Windowsでもバイナリファイルをアップロードする準備をしてください。
同じことが外部プログラムにも当てはまります。 ライブラリで解決できるタスクの使用を最小限に抑え、外部プログラムは複雑なタスクにのみ使用してください。
コンパイル時または実行時?
多くの場合、ある種のOSで作業するとき、OS固有のコードをどのように記述するか疑問に思います。 ある点を満たすために必要なのはプラットフォーム固有のコードかもしれません。 例を挙げましょう。 次の機能。 多くのことを行いますが、要件の1つは、Windows以外のプラットフォームでは、ファイルを読み取り専用で作成する必要があることです。 2つの実装を見てみましょう。
func example() { filename := "myfile.txt" fi, _ := os.Stat(f)
これにより、実行時にプログラムがWindows上で実行されているかどうかがチェックされます。
これと比較してください:
func example() { filename := "myfile.txt" fi, _ := os.Stat(f) setNewFileMode(f, fi) }
多くの人が言うように、最新バージョンはこれを行う必要があります。 これが常に最良の解決策とは限らないことを示すために、意図的に例を複雑にしました。 私にとっては、最初のオプションが好ましい場合があります。特にそのようなコードの場所が1つしかない場合-これが短い場合、コードが何をするかを確認するためにいくつかのファイルを調べる必要はありません。
私はそれぞれのアプローチのマイナスとプラスで小さなタブレットを作りました。
「コンパイル時」の長所 | 「実行時」の長所 |
最小限のオーバーヘッドまたは欠落したオーバーヘッド | すべてのコードを1か所に保管できます |
プラットフォームごとに個別のファイルのコード | 一部のエラーは、クロスコンパイルせずに検出できます。 |
すべてのプラットフォームでコンパイルされないインポートを使用できます | |
「コンパイル時」の短所 | 「実行時」の短所 |
コードの複製が必要になる場合があります。 | プラットフォーム固有のコードがどこにあるかを確認する簡単な方法はありません |
多くの小さなファイルにつながる可能性があり、多くの機能が分散した1つの大きなファイルにつながる可能性があります | チェックするためのわずかなオーバーヘッド |
コードを表示するには、いくつかのファイルを開く必要があります | プラットフォームに依存しない構造/機能は使用できません |
クロスコンパイルを使用して、コードが実行されることを確認する必要があります | |
一般に、テストを作成する場合を除き、コンパイル時に異なるファイルでチェックすることをお勧めします。 ただし、場合によっては、実行時に確認することをお勧めします。
クロスプラットフォームテストのCI構成
結論として、クロスプラットフォームテストを構成します。 これは
resticから学んだ便利なことの1つであり、クロス
コンパイルはすでに構成されています。 Go 1.5がリリースされると、設定する身体の動きがさらに少なくなるため、クロスプラットフォームコンパイルがさらに簡単になります。
同時に、Goの古いバージョンについては、クロスコンパイルの自動化に役立つ
goxを見ることができます。 さらに高度な機能が必要な場合は、
goxcをご覧ください 。
ハッピーコーディング!
著者から: