C++ の Hello World とグラス オブ ワイン、オーマイ !

#include <iostream>

int main() {
 std::cout << "Hello, World\n";
}

削除するものも、追加するものもありません。

これが正しい「Hello World」です 」を C++ で。その他すべて Hello World 間違っている .しかし、これは名前空間 std の使用方法について私が暴言を吐く場所ではありません。 C++ の教えで台無しにされたすべてを結晶化します。またの機会に。

今日は、hello world をコンパイルします。 ターゲット システムで実行できるようにします。

しかし、最初に、私についていくつかお話しさせてください。私は楽しみと利益のために Linux を使用しています。最高のシステムだと思います。私のため。開発者として。ときどき、Windows を使用している開発者を見下すことがあります。また、Arch の vim ユーザーは、Ubuntu を使用している私を見下している可能性があります。完璧な人はいません。

とにかく、ターミナルを起動しましょう

# sudo apt-get install g++
# g++ -o helloworld helloworld.cpp
# ./helloworld
Hello, World!
#

いいですね、それは簡単です、家に帰ってビールを飲みましょう 🍻 !

しかし、その後、私の上司に入ります。彼らは、Windows を使用する人々にソフトウェアを販売するビジネスを行っています。私は彼らに、牛にしゃべらせることができること、端末のサイズを変更できることを示そうとしています。そうすれば、明らかにすべてのビジネスを一度に Linux に移行する必要があります。

エッシャーの絵に閉じ込められたようにしばらくお互いを見下ろした後、私はクライアントを幸せにする仕事をしていることをしぶしぶ思い出したので、hello world Windows へのアプリケーション。私たちの上司は、その画期的なアプリを作成するためにどのような環境を使用するかは気にしませんし、同時に Linux 版の作業を続けることに問題はありません。そのため、そのアプリケーションを Windows 用に開発することにしました。 オン Linux;何が問題になる可能性がありますか?

さらに、ビルド ファームと継続的インテグレーションのセットアップがはるかに簡単になります。制御された新しい環境で Windows アプリをビルドするために、CI に新しい Docker コンテナーをオンザフライでプロビジョニングさせることもできます。私は、Docker はカーゴ カルトのようなものだと考えがちですが、Jenkins と一緒に Docker を使用することは、実際には非常に理にかなっています。また、システム管理者が気に入った場合は、Windows サーバーの処理を強制しないでください。

アプリケーションを可能な限り移植可能にし、プラットフォームにとらわれないように努力する必要があるため、アプリケーションの Windows バージョンを使用すると、実際にはコードが改善される可能性があります。そう自分に言い聞かせようとしています。

結局のところ、Microsoft は msvc と呼ばれる Windows 用のコンパイラを提供するほど親切であり、Windows では g++ よりも msvc の方が適していると感じています。これは、エコシステム全体が設計されているコンパイラだからです。また、Microsoft が独自のツール、フォーマット、呼び出し規約を最もよく知っていることを願っています。私はそれをベンチマークするために余計な努力をしたことはありませんが、インターネット上でどちらのアプローチの支持者も見つけることができます.しかし、MSVC チームは私に同意します。ショッカー。

とにかく、今のところ、それに固執しましょう。

# apt-get install msvc
E: Unable to locate package msvc

驚くべきことに、それはうまくいきません。試したことで男を責めることはできません。しかし、その理由を説明するために、コンパイラがどのように機能するかを説明しましょう.

コンパイラはファイルを開き、そのファイルの内容を実行可能なものに変換し、それを別のファイルに書き出します。場合によっては、複数のソース ファイルがあるため、一連のファイルを開いて実行可能ファイルを書き出すプログラムであるリンカが必要になります。実行可能ファイルはファイルであり、魔法のようなものではありません。ライブラリが必要な場合もあります。ライブラリはファイルです。そして、ほとんどの場合、ファイルである大量のヘッダーが必要になる可能性があります。普通の古い退屈なファイル。実行可能ファイルは、ファイルでもある別の実行可能ファイルによってロードされます。そうじゃないかもしれませんが、Plan 9 にはもっと多くのファイルがあります。

明確にするために言うと、コンパイラ、特に C++ コンパイラはエンジニアリングの非常に複雑な部分であり、出会うすべてのコンパイラ ライターに Cookie を提供する必要があります。ただし、システム統合の観点からは、それらは取るに足らないものです。ほとんどのコンパイラは、スレッドを気にすることさえありません。それらはビルドシステムにそれを処理させます。残念なことに、ほとんどのビルド システムは靴ひもを結ぶ方法をまだ学習していません。

とにかく…これはコンパイラを書くために必要なカーネル機能のリストです:

    <リ>

    ファイルを開く、読む、書く

    <リ>

    ディレクトリの内容を読む

    <リ>

    メモリの割り当て

したがって、これは妥当なリストであると考えているかもしれません。そのため、msvc が Linux で利用できないのはなぜだろうかと疑問に思うかもしれません。確かに、msvc に Linux/ELF アプリケーションをビルドさせるのは大規模で、おそらく無意味な作業になるでしょうが、目的はアプリケーションをビルドすることだけです。 Windows、そして Microsoft は私がそうするのを可能な限り簡単にしてくれるはずですよね?

しかし、このことはあります。 Windows は 「エコシステム」 です .つまり、ユーザーと開発者の両方に OS を販売し、ツールを開発者に販売し、他の OS の伝説が語っていることを誰も知らないようにしたいということです。したがって、Windows アプリケーションを作成する場合は、Windows が必要です。くそ。

幸いなことに、誰かが Linux で Windows を書き直して、それをワインと呼びました。おそらく、それをすることを考えるだけでも、彼らは非常に酔っていなければならなかったからです.ワインが 1.0 に到達するのにかかった時間はわずか 15 年でした。でも今は3.0だから使えるかも?オープン ソース コミュニティには小さな奇跡があり、WINE は確かにその 1 つです。

非常に長い間、MSVC は Visual Studio にバンドルされていました。つまり、Windows で Qt クリエーター、CLion、Eclipse、または notepad++ を使用して C++ アプリをコンパイルする場合でも、Visual Studio が必要でした。生態系とそのすべて。

状況は改善されました。「ビルド ツール」をインストールして、約 5 GB の… スタッフをインストールするだけで済みます。そうしましょう。

ああ、どうやらコンパイラは実行可能ファイルとして配布されており、インターネット経由で要求していないものをダウンロードします。 40GB zip よりも優れているのではないでしょうか?

# wine vs_BuildTools.exe
The entry point method could not be loaded

びっくりした?私の夢は打ち砕かれます。私たちは行います Windows 開発を行うには Windows が必要です (ネタバレ:良くなります)。

VM を起動しましょう。従う場合は、新しいまたは複製された Windows 10 VM を使用することをお勧めします。私たちは多くの奇妙なものをインストールする予定であり、自分でクリーンアップすることはほとんど不可能です.その後、VM を取り除くことができます。

それが完了したら、VS ビルド ツールをダウンロードします。

手根管が表示されるまで下にスクロールします。ビルド ツールは最後から 2 番目の項目です。それをダウンロードしてください。

インストーラーの起動にいくつか問題がありました。彼らは、広告サーバーのリストに自分自身を入れることができたサーバーに接続しようとしたため、私のDNSがそれをブロックしたと思います.聞かないでください。

ロード画面のあるインストーラー、それは完全に正常です。完了すると、メインの UI がロードされます。ゆっくりと苦痛を伴いますが、その後、チェック ボックスをオンにします。とても楽しいです。

静的解析ツールは必要ありませんが、コンパイラをインストールすると必ずチェックされます。大丈夫です。

C++ ツールセットが必要です — 他の人がツールチェーンと呼んでいるものです。 v141 と 15.4 v14.11 のどちらが新しいかはわかりません。サイコロを使いますか?

C ランタイムも必要です。これは便利です。 CRT と URT のどちらが必要なのかわからないので、両方をインストールします。ただし、URT/CRT は便利です。存在する前は、すべてがはるかに困難でした.

最後に、いくつかの Windows 機能を使用する必要がある可能性があるため、Windows SDK を入手する必要があります。どうやらそれはいくつかのC#コンポーネントに依存しています。いくつかの JS ライブラリ、*明らかに。 *はっきりさせておきますが、Windows SDK がなければ、リモートで役立つことは何もできません。今すぐ入手してください。

Visual Studio がハード ドライブの隅々まで入り込んでいる間、コーヒー ポットを飲む時間です。ただし、ある時点で、蝶と一緒​​に自転車に乗ることができるようになります。いいね。

Linux を捨てたいと思うほどのバタフライでは足りないので、インストールしたばかりのものが Windows ボックスなしで使用できるかどうか見てみましょう。

以下を VM の外部にコピーします:

    <リ>

    C:\Program Files (x86)\Windows Kits\10\Include

    <リ>

    C:\Program Files (x86)\Windows Kits\10\Lib

    <リ>

    C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC

最初の 2 つのパスは Windows SDK で、最後のパスはすべてのアーキテクチャのコンパイラ、リンカー、STL、および VC ランタイム ライブラリを含むツールチェーンです。

私のインストールでは、あちこちに URT ファイルがあります。そのため、Windows 10 SDK をインストールすると実際に CRT が取得されるので、インストールするコンポーネントを選択するときに個別にアクティブ化する必要はないと思います。ほんの数年前と比べると、状況ははるかに良くなっています。 Microsoft は多忙を極めています。

すべてをwindowsというフォルダーに入れ、ランタイムを含むmsvcコンパイラー、STLと再頒布可能ファイルを片側に、windows 10 SDKを別のフォルダーに入れます。使用していた SDK またはツールチェーンのバージョンに関する情報を保持していませんでした。より適切に保持することをお勧めします。

Windows Sdk には、rc.exe のような便利なバイナリと dll がいくつかあります。cl.exe を含むツールチェーン バイナリが配置されている msvc2017/bin/Hostx64/x64 に配置してください。

Windows 開発に慣れていない場合:

    <リ>

    cl.exe はコンパイラです

    <リ>

    link.exe はリンカーです

    <リ>

    rc.exe は、アイコンやマニフェストなどのリソース ファイルを処理するツールです

ドライバー、cab ファイル、MSI インストーラーなどを処理する必要がある場合は、他のさまざまなツールが必要になる場合があります。

全体で約 2.9GB です . Windows VM にインストールする必要があったものの約半分です。

またワインを飲みましょう🍷。 https://wiki.winehq.org/Ubuntu および https://github.com/Winetricks/winetrics にアクセスして、ワインのセットアップが最新であることを確認してください。 wine-3.0 を使用します。

次に、VC 2017 の再頒布可能パッケージをインストールします。プロセスはほとんど自動です。すべてをコーシャに保つために、専用のワイン プレフィックスを使用します。これが意味することは、windows に複数の msvc をインストールする方が、windows にインストールするよりも実際には簡単だということです。

WINEPREFIX=windows/vs-buildtools2017-wine64 WINEARCH=win64 winetricks vcrun2017

次に、windows フォルダーに bin64 フォルダーを作成します。このフォルダーには、次の内容の小さな bash スクリプトを記述できます。


#!/bin/bash
set -ex
DIR="/home/cor3ntin/dev/cross-compilers/windows/bin64"
export WINEPREFIX="$DIR"/../vs-buildtools2017-wine64
export WINEARCH=win64
export WINEDEBUG=-all
PROGRAM=$(readlink -f "$0")
PROGRAM=$(basename "$PROGRAM")

ARGS=( "$@" )
x=0;
while [ ${x} -lt ${#ARGS[*]} ]; do
 if [[ "${ARGS[$x]}" == '/'* ]] && [ -e "${ARGS[$x]}" ]; then
 ARGS[$x]=$(sed 's/\//\\/g' <<< "${ARGS[$x]}" )
 fi
 x=$((x + 1))
done

wine "$DIR"/../msvc2017/bin/Hostx64/x64/$PROGRAM ${ARGS[@]}

そのスクリプトは、最初にプレフィックスを使用するように wine を設定します。次に、ワインで実行されている実際の Windows PE バイナリに引数を転送する前に、Linux から Windows へのパス セパレータ変換 ( / から \ へ) を行います。

shc というツールを使用して、そのラッパーを適切な elf 実行可能ファイルに変換します。そうしないと、今後問題が発生する可能性があります。別の解決策は、bash の代わりに C++ ラッパーを作成することです。 shc には、ハードコードされたインストール パスが必要なことから始めて、いくつかの欠点があります。

shc -f cl-wine.sh -o cl.exe
shc -f cl-wine.sh -o link.exe

最後の行を wine “$DIR”/../msvc2017/bin/Hostx64/x86 に変更するだけで、同じ方法で bin32 フォルダーを作成できます。 /$プログラム

x86 ターゲット コンパイラを使用する。別のアーキテクチャをサポートするために 2 つの個別のバイナリ セットが必要な理由はわかりませんが、私たちはそうしています。最後に、x86 リンカはライブラリが見つからないというエラーを出す可能性があるため、いくつかのシンボリック リンクを作成します。

cd windows/msvc2017/bin/Hostx64/x86/
for x in $(ls ../x64/ms*.dll); do ln -s $x .; done

本格的な作業を行う前に、最後にもう 1 つ。動作しないため、vctip.exe を削除する必要があります。これはテレメトリ ツールなので、必要ありません。これは、windows/msvc2017/bin/Hostx*/** にあります。この手順に従わないと、奇妙なスタック トレースが表示されます。

Hello World アプリケーションを作成します。それは実際には簡単です

windows/bin64/cl.exe \
 /nologo /EHsc \
 test/helloworld.cpp \
 /I windows/msvc2017/include/ \
 /I windows/sdk_10/include/ucrt/ \
 /link \
 /LIBPATH:windows/msvc2017/lib/x64/ \
 /LIBPATH:windows/sdk_10/lib/um/x64 \
 /LIBPATH:windows/sdk_10/lib/ucrt/x64 \
 /out:helloworld.exe

コンパイラ ヘッダー ( STL を含む)、C ランタイム、および kernel32.lib などの一部の Windows ライブラリに依存する実行可能ファイルを作成しています。

完全を期すために、ここに x86 ビルドを示します

windows/bin32/cl.exe \
 /nologo /EHsc \
 test/helloworld.cpp \
 /I windows/msvc2017/include/ \
 /I windows/sdk_10/include/ucrt/ \
 /link \
 /LIBPATH:windows/msvc2017/lib/x86/ \
 /LIBPATH:windows/sdk_10/lib/um/x86 \
 /LIBPATH:windows/sdk_10/lib/ucrt/x86 \
 /out:helloworld.exe

真実は、全体の試みはかなり単純であり、おそらくウィンドウを適切に使用するよりも単純です. vcvarsall.bat と、perl、git、python、sed、ターミナル、zsh などのすべてのお気に入りのツールをいじる必要はありません。適切に動作します。

🔨 ビルド システム

Linux で cl.exe が動作するようになりました。先に進む前に、そのエイリアン ツールチェーンを優れた最新のビルド システムに追加する必要があります。私は cmake のホットメスに対処する気分ではないので、QBS を使用します。 、私のお気に入りのビルド システムです。

wine/msvc コンパイラーを使用するように qbs をセットアップするのは簡単です…

QBS はツールチェーンを自動的に検出できますが、いくつかの問題があります。まず、ツールは MSVC が Windows 上にのみ存在すると想定しているため、一部のコード パスは無効になっています。これは数時間で修正できると思います。移植可能な方法で CommandLineToArgv 関数を実装するだけで済みます。

ただし、ツールが巧妙すぎることについては、言いたいことがあります。 QBS は、想定される場所で vcvars.bat を解析しようとします。これは、喜んで削除したファイルの 1 つです。

リアリティチェック、自動検出は一切行われません。その必要はありません。ツールチェーンを手動でセットアップし、msvc-on-windows-proper とは別のものとして扱うことができます。インクルード ディレクトリとライブラリ パスがいくつかあるだけなので、検出は実際には問題になりません。

いくつかのファイルを GitHub にプッシュし始めました。これは非常に進行中の作業です。現時点では、デバッグ ビルドは完全に壊れています。これは、ワイン ツールチェーンをある程度理解するためのモジュールです。ほとんどの場合、すべてのプローブを無効にし、すべてが既に適切に構成されていると想定します.cor3ntin/qbs-wine-toolchain

そのため、プロファイルを手動で設定するすべての作業を行う必要があります。しかし、私たちの努力が何かを証明したとすれば、VC++ のように毛むくじゃらのツールチェーンでさえ、ほんの一握りの変数 (コンパイラ、リンカー、ツール パス、インクルード、定義、ライブラリ パス) に削減できるということです。これが私の QBS プロファイル構成です。

最後に、小さな qbs ビルド スクリプトを記述できます

import qbs 1.0

CppApplication {
 name : "helloworld"
 files : ["helloworld.cpp"]

 Group {
 name: "app"
 fileTagsFilter: "application"
 qbs.install: true
 qbs.installDir: "bin"
 }
}

これを実行すると、出来上がり

runner.sh は、新しくビルドされた Windows 実行可能ファイルを起動する前に、wine プレフィックスを設定する小さなスクリプトです。派手すぎない。

だからここにあります。 ELF にコンパイルされた bash スクリプトにラップされた Microsoft コンパイラは、Linux で実行される最新のビルド システムによって駆動され、64 ビット PE 実行可能ファイルをビルドします。とても満足です。

仮想の上司がドアをノックしています。パート 2 でお会いしましょう。