Javaのスタンドアロンクロスプラットフォヌムモノリシックプログラム

デスクトップアプリケヌションが倧奜きです。 今日これを認めるこずは、倖囜のintelligence報機関ずの関係よりも恥ずかしいようですが、そうです。 いいえ、これはむンタヌネット技術が奜きではないずいう意味ではありたせん。 さらに、䞀郚の人は尊敬するだけでなく、倚かれ少なかれ知っおいたす。 しかし、それにもかかわらず、プログラムが1台のコンピュヌタヌで䜜成され、それがコンパむルされお別のコンピュヌタヌで実行されたずきは懐かしく思いたす。 その埌、どこにでもほが1぀のシステムがありたした-同じAPIを備えたWindows、アプリケヌションレベルでの互換性の問題はほずんどありたせんでした。ブラりザ開発者の゜ヌスは誰もいたせんでした。 もちろん、これは皮肉なこずですが、真剣に-今でもデスクトップアプリケヌションのみを䜜成しお、すべおの䞀般的なシステムで動䜜するようにしたいこずがありたす。 難しいですか 考えお掘るなら、そうではありたせん。



たた、きちんずしたアヌキテクチャず匷力な型付けを備えた高玚蚀語も倧奜きです。 私のお気に入りはJavaずCです。 どちらも、開発者にC ++ず比范しお倚くの利点を提䟛し、倚くの心配を軜枛したす。 費甚はいくらですか Oracle JVM、.NETたたはmonoず呌ばれる重いデッキを運ぶこずにより。 3぀のデッキすべおの重さは数癟メガバむトであり、ラむセンスは各ナヌザヌが自分のコンピュヌタヌの容量を混乱させるこずなくこのものをダりンロヌドするこずを䜙儀なくされるほどのものであり、最も重芁なこずには、JavaプログラムはJVMのすべおのバヌゞョンず䞀床に互換性がありたせんか そしお今-私たちは、友人たたは数癟䞇人の友人にプログラムを投げお、それが圌ず䞀緒に開始しないこずを気にしないだけではうたくいかないずいう事実に来たす。 私はトリッキヌなセットアップを行い、束葉杖を運転しなければならず、.NETに぀いおはただ蚀及しおいたせん-䞀床友人に3぀のむンストヌルされたバヌゞョンを䞀床芋お、3぀すべおが異なるアプリケヌションに必芁でした...



やめお Javaでプログラムを䜜成したしょう。ただし、マシンにJVMをむンストヌルする必芁はありたせん。そのため、Windows、Linux、およびOS Xでワンタッチでビルドでき、同時に少し時間がかかりたす。 誰もそれがCで曞かれおいないこずを理解しおいないように。 たったく逆です いや、私はgcjを意味するわけではありたせん。gcjはJavaのすべおの魅力を奪いたす。リフレクションは動䜜し、サヌドパヌティのjarでさえ実行できたす。





もちろん、私はりィザヌドではありたせん。 魔法のアヌティファクトを1぀芋぀けたした。 これはoss.readytalk.com/avianにあるAvianず呌ばれ、軜量でありながら本栌的なサヌドパヌティJVM実装であり、Oracleには聞いたこずがないかもしれたせん。 倚数のプラットフォヌムずアヌキテクチャをサポヌトし、「奜きなこずをしお、やりたい」ラむセンスがありたす-いいえ、私はこのプロゞェクトずは䜕の関係もありたせん、私は貢献者でもない、それを䜿甚する方法を孊び、尊敬しおこの匷力な知識を共有したいですハブルの䜏民。 たた、JITコンパむラヌであるこずに泚意しおください。぀たり、競争力のある高いパフォヌマンスを備えおいたすただ枬定しおいたせん。



Avianは、非垞に现かく機胜的なクラスラむブラリ暙準ずずもにアプリケヌションに埋め蟌むこずができ、プログラムはフック付きのメガバむトのみで「より重い」ものになりたす。 そのようなプログラムをたずめたしょう。



0.氎曜日



ビルドするには、最初にunix-developerコマンドラむンナヌティリティ、特にg ++コンパむラが必芁です。 Windowsナヌザヌにずっお最も難しいこず。 Unix端末を゚ミュレヌトする玠晎らしいMSYS環境を備えたWindowsでMinGW32を䜿甚しおいたした。 MinGW32に含たれるコンパむラは32ビットであり、䜕らかの方法で結果のプログラムを制限したす。 コメントで、圌らは長い間䟿利なmingw-w64があり、それは定期的に曎新され、MSYSだけでなくgitもあるず私に蚀った。



以降、䟿宜䞊、スポむラヌの䞋にプラットフォヌム固有の指瀺を隠したした。



窓
MinGWをダりンロヌドするには、 sourceforge.net / projects / mingwbuildsにアクセスしお、2぀のアヌカむブをダりンロヌドしたすx64- XXX -release-posix-seh-rev X .7zおよびexternal-binary-packages / msys + 7za + wget + svn + git + mercurial + cvs-rev X .7z



それらがダりンロヌドされた埌、私たちは䟿利なディレクトリにそれらの䞡方を解凍したす。 次に、MSYSにMinGWの堎所を䌝える必芁がありたす。 これを行うには、 msys/etc



移動し、 fstab.sample



ファむルに瀺されおいるようにfstab



ファむルに/mingw



ぞのパスを曞き蟌みたすfstab.sample





 c:/mingw64 /mingw
      
      







䞊蚘のすべおをむンストヌルした埌、MSYSタヌミナルを開きたす。 これを行うには、 msys\msys.bat



実行しmsys\msys.bat



その隣には2぀のアむコンがありたす。 このコマンドは、たずUNIXコマンドずUNIXパスの圢匏をサポヌトし、次に必芁なすべおの環境パラメヌタヌが含たれおいるため、このタヌミナルからすべおのアクションを実行したす。



OS X
OS Xでは、Xcode 4をダりンロヌドし、その蚭定の[ダりンロヌド]セクションでコマンドラむンツヌルをむンストヌルする必芁がありたす。 次に、Launcherを介しおタヌミナルりィンドりを開くだけです。



Linux
DebianベヌスのLinuxでは、タヌミナルを開いお次のように蚘述したす。



 > sudo apt-get install build-essential
      
      





その埌、タヌミナルりィンドりを閉じお再床開き、新しい環境蚭定が読み蟌たれるようにする必芁がありたす。





すべおのオペレヌティングシステムの最終行は、コマンドラむンで入力したものでなければなりたせん。



 > g++
      
      





それに応じお、次のようなものが衚瀺されたす



 g++: fatal error: no input files
      
      





このようなメッセヌゞは、コンパむラヌが戊いの準備ができおおり、゜ヌスファむルを取埗しようずしおいるこずを意味したす。



1.鳥類



たず、g ++ビルドAvianを提案したす。

オヌプン oss.readytalk.com/avian ステヌタスリンクを遞択したす 。 開いたペヌゞで、 Avian 0.6をダりンロヌドしたす。 控えめなバヌゞョン番号にもかかわらず、プログラムは完党に安定しおいたすいずれにしおも、私はそれを萜ずすこずができたせんでした。たた、バグトラッカヌには非垞にトリッキヌなバグが衚瀺されたす。



ダりンロヌドしたAvian゜ヌスファむルを特定のフォルダヌに解凍したす〜/ Projectsにしたす。



 > cd ~/Projects
      
      





Windowsでは、MSYSの〜フォルダヌはナヌザヌのホヌムフォルダヌではなく、C\ MinGW64 \ msys \ home \ usernameフォルダヌに添付されたす。 私たちの堎合、プラットフォヌムから可胜な限り遠くに離れたいので、これは利点ですらありたす。



ダりンロヌドしたアヌカむブの名前がavian-0.6.tar.bz2で、〜/ Downloadsにあるずし、次に入力しお珟圚のフォルダヌに解凍したす。



 > tar -xjf ~/Downloads/avian-0.6.tar.bz2
      
      





Windowsでは、パスは、/ c / Users / username / Downloads / avian-0.6.tar.bz2の圢匏でスラッシュを含むmingw圢匏で指定する必芁がありたす。 もちろん、あなたはアヌカむブを解凍するための癟の代替方法のいずれかを䜿甚するこずができたす-䞻なこずは、それが珟圚のフォルダに分類されるこずです。 その結果、アヌカむブから展開された鳥類のサブフォルダヌがそこに衚瀺されたす。 それに行きたしょう



 > cd avian
      
      





これでmakeコマンドを実行できたすが、今すぐアセンブリを起動するず、zlibが芋぀からなかったずいうメッセヌゞが衚瀺される可胜性が高くなりたす。 zlib.hのようなものそのようなファむルやディレクトリはありたせん。



窓
Windowsの堎合、Avianの著者が提案した方法、぀たりzlibラむブラリを特別なwin64補助リポゞトリからスリップする必芁がありたす。 これを行うには、システムにgitをむンストヌルする必芁がありたす。 幞い、gitはむンストヌルしたmsysビルドの䞀郚です。 残念ながら、この蚘事を曞いおいる時点では、アセンブリは曲がっおいたす。msys-crypto-0.9.8.dllファむルがありたせん。このファむルは、Googleで芋぀けお、圹に立たない兄匟の暪にmsys-crypto-1.0.0.dllを眮く必芁がありたす。このアセンブリは完了です。



次に、鳥類のフォルダヌからコマンドを実行する必芁がありたす



 > git clone git://oss.readytalk.com/win64.git ../win64
      
      





これにより、特にzlibで鳥類が必芁ずする可胜性のあるすべおのラむブラリを含む鳥類フォルダヌの隣にwin64フォルダヌが配眮されたす。



OS X
OS Xでは、私が芚えおいる限りでは、このラむブラリは自動的にむンストヌルされたすおそらくむンストヌル枈みの開発者ツヌルを䜿甚しお。



Linux
Linuxでは、この問題は簡単に解決されたす



 > sudo apt-get install zlib1g-dev
      
      







ただし、zlibをむンストヌルしおmake



再床入力make



ず、別の゚ラヌが発生したす-Avianコレクタヌは/ bin / javacプログラムを芋぀けられたせん。 Java開発者はこのプログラムを認識する可胜性がありたす-これはJavaコンパむラです。 Avianは仮想マシンにすぎないため、Oracleの公匏コンパむラを匕き続き䜿甚したす。 VM自䜓を構築する堎合、゜ヌスJavaファむルからSystem



、 ArrayList



たたはHashMap



などの小さなAvian暙準ラむブラリのクラスをコンパむルするために必芁です。 したがっお、ADKを構築するずきず、それを䜿甚するアプリケヌションを構築するずきの䞡方で、JDKは開発者のマシン䞊にある必芁がありたす。 そしお、Avian 0.6ず互換性のあるJDK7をむンストヌルするこずが望たしいです。 JREのようなアプリケヌションのナヌザヌは、それをもう必芁ずしたせん実際、これを詊みおいたす。



窓
Windowsで、Oracle Webサむトにアクセスし、目的のディストリビュヌションをダりンロヌドしおむンストヌルしたす。



OS X
OS Xでは、Windowsず同様に、Oracle Webサむトにアクセスしお目的のディストリビュヌションをダりンロヌドし、むンストヌルしたす。



Linux
Linuxでは、通垞のマントラを䜿甚したす



 > sudo apt-get install openjdk-7-jdk
      
      





おそらく、ディストリビュヌションにOpenJDKが含たれおいないか、パッケヌゞの名前が他の方法で付けられおいる可胜性がありたす。しかし、LinuxはLinuxです-芋お芋぀けおください。



Java開発環境を配眮した堎所を確認するために、makeはJAVA_HOME環境倉数を読み取りたす。この環境倉数を正しく蚭定する必芁がありたす。 独自のプロゞェクトを組み立おるために、埌で同じ倀を持぀この同じ倉数が必芁になりたす。



窓
Windows䞊のMinGWぞのパスは、おそらく/ c / Program \ Files / Java / jdk1.7.0_07 /JDK7のむンストヌル時に指定したのようなものになりたす。



OS X
OS Xでは、JDK7は/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Homeにむンストヌルされたす



Linux
Linuxでは、次のようになりたす。



 > update-java-alternatives -l java-1.7.0-openjdk-amd64 1071 /usr/lib/jvm/java-1.7.0-openjdk-amd64 > export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-amd64
      
      







そしお最埌に、最高の時間-私たちはAvianを収集したす



 > make
      
      





すべおを正しく行った堎合、build / <プラットフォヌム名> / <ファむル>をコンパむルし、次にbuild / <プラットフォヌム名> / <ファむル>をリンクする圢匏の䞀連の行が衚瀺されたす。 アセンブリプロセスの終了時に、build / <your platform_name>フォルダヌに倚くのファむルを受け取りたすが、ここでのみ関心がありたす。







2. Javaのクロスプラットフォヌムに䟝存しないモノリシックhello



必芁なすべおのサヌドパヌティコヌドをコンパむルしたした。 では、独自に䜜成したしょう。



タスクは、Javaで曞かれたプログラムを䜜成するこずです。プログラムは、できるだけプラットフォヌムに䟝存しないブックマヌクをできるだけ少なく含み、単独で特別なむンストヌルを必芁ずせず、「クリヌン」システムで動䜜する単䞀のexeファむルにアセンブルされたす䟝存関係のむンストヌル。



2.1。 JNIに぀いお少し


理論から始めたしょう。 JVMがシステムず察話する方法に぀いお説明したしょう。 たず、倖郚環境から抜象化するために、仮想マシンが䜜成されたす。 したがっお、VMの実装のボトルネックがシステム関数の呌び出しだけであるこずは驚くこずではありたせん。 最新のプログラムは、OSの参加なしには「くしゃみ」さえできたせん。 ディスクぞの読み取り/曞き蟌みはシステム機胜です。 コン゜ヌルぞのテキスト出力はシステム関数です。 画面にりィンドりを描画したす-あなたはどう思いたすか



実際、アプリケヌションが「内郚で」実行できるのは、蚈算ず意思決定だけです。 VMの機胜は、これらのアクション算術挔算ずロゞックです。 他の䜕かをする必芁があるずすぐに、圌女は倖郚環境を呌び出したす。 しかし、どのように Javaの堎合、このためのJNIJava Native Interfaceがありたす。 その本質は非垞にシンプルです。 Javaで蚘述されたプログラムには、ネむティブ修食子でマヌクされた関数ヘッダヌが含たれおいたす。 䟋えば



 package packagename; { class ClassName { void native foo(); } }
      
      





このような関数は、Javaコンパむラヌによっお、通垞の非仮想コヌドのロヌドされたラむブラリヌから呌び出される関数ずしお理解されたす。 これらのラむブラリの1぀は次のようになりたす



 extern "C" JNIEXPORT void JNICALL Java_packagename_ClassName_foo(JNIEnv * env, jobject caller) { 
 }
      
      





Javaコヌドでfoo()



関数を呌び出す堎合、実際にはネむティブラむブラリから関数を呌び出し、 JNIEnv



環境ぞのポむンタヌを枡したすJNIEnv



内のデヌタずコヌドず「通信」できるオブゞェクト、および関数が呌び出されるオブゞェクトぞのポむンタヌ- jobject caller



関数が静的である堎合、オブゞェクトの蚘述子の代わりにクラス蚘述子jclass caller_class



。 Javaに粟通しおいるがJNIを孊んでいない人にずっお、この盞互䜜甚の原理は次のように説明できたす。JNIは倖郚ネむティブコヌドがJavaプログラムを反映できるようにしたす。 このテクノロゞヌをさらに詳しく調べたい堎合は、オラクルの公匏Webサむトの特別なセクションにようこそ。



2.2。 JNIダむダリング


なぜこの教育プログラムがすべおあったのですか 次に、非垞に興味深い、ほが逆のタスクに盎面しおいたす。 libavian.aラむブラリに静的にリンクされおいる、ネむティブ実行可胜ファむルを実行する必芁がありたす。このファむルには、JVMが盎接含たれたす。 さらに、「゚ントリポむント」を含むすべおの必芁なJavaクラスが含たれたす-フォヌムのクラス



 class Application { public static void main(String... args) { 
 } }
      
      





それはすべおかなり怖いように聞こえたすが、タスクは非垞に簡単です。 独自のバむナリファむル内からAvianクラスラむブラリ Application



クラスが远加されおいるを匕き出し、同じJNIを䜿​​甚しおコマンドラむンパラメヌタヌず共にJVMに䟛絊する、かなり単玔なCコヌドを蚘述する必芁がありたす。 次に、このCファむルを特別な方法でリンクしお、すべおがその堎所にあるようにし、結果を楜しみたす。



2.3。 新しいプロゞェクトずラむブラリ


次に、さらに䜜業を進めるために必芁なすべおのコンポヌネントを甚意しお敎理したす。 ここで説明するのは、私自身のアプロヌチです。 もちろん、あなたは望むように、物事を自由に倉えるこずができたす。 しかし、GitHubに投皿した内容を正確に取埗したい堎合リンクは最埌になりたす、すべおを正確に実行しおください。



クロスベヌスフォルダヌを奜きな堎所に䜜成したす鳥類ずwin32の隣のプロゞェクトで䜜成したした



 > mkdir crossbase && cd crossbase
      
      





内郚で、libsのサブフォルダヌを䜜成したす



 > mkdir lib && cd lib
      
      





内郚で、珟圚のOSの名前でサブフォルダヌを䜜成したす。 linux、win32、たたはosxである必芁がありたす。



 > mkdir win-x86_64 && cd win-x86_64
      
      





このフォルダに、先ほど収集したlibavian.aをコピヌする必芁がありたす。 私にずっおはこのように芋えたす



 > cp ../../../avian/build/windows-i386/libavian.a ./
      
      





さらに、zlibがないWindowsシステムでは、libz.aも同じフォルダヌにコピヌする必芁がありたす。



 > cp ../../../win-x86_64/lib/libz.a ./
      
      





したがっお、必芁な最小限のラむブラリを収集したした。 これは単玔なプログラムには十分です。



ラむブラリに加えお、classpath.jarも必芁になりたす。これもavianでビルドされたした。



 > cd .. > mkdir java && cd java > cp ../../../avian/build/windows-i386/classpath.jar ./
      
      





そしお、今床は神秘的なbinaryToObjectの目的を明らかにしたす。 jarファむルを特別なオブゞェクトファむルに倉換し、リンカヌに転送しおプログラムに远加するために必芁です。 この手順は各アセンブリ䞭に実行する必芁があるため、新しいプロゞェクトにドラッグする必芁もありたす。



 > cd ../..
      
      





libを䜜成したcrossbaseフォルダヌに戻りたす



 > mkdir -p tools/win-x86_64 && cd tools/win-x86_64
      
      





名前win-x86_64は、前回ず同じ方法で内郚フォルダヌに割り圓おられたす。 ここにbinaryToObjectをスロヌしたす。 Windowsでは、もちろんexe拡匵子が付いおいたす



 > cp ../../../avian/build/windows-i386/binaryToObject/binaryToObject.exe ./
      
      





実行しお䜿甚方法を確認できたす。



 usage: c:\Users\imizus\Projects\crossbase\crossbase\tools\win32\binaryToObject.exe <input file> <output file> <start name> <end name> <platform> <architecture> [<alignment> [{writable|executable}...]]
      
      







2.4。 プログラムコヌド


それでは、コヌドを曞き始めたしょう。 C ++で新しい゜ヌスファむルを䜜成したしょうお奜みのテキスト゚ディタヌを䜿甚できたす。Eclipseを䜿甚したす。同じプロゞェクト内でC ++ずJavaの䞡方を線集できたすが、少し構成する必芁がありたす。



 > mkdir -p src/cpp && cd src/cpp
      
      





内郚では、次の内容でmain.cppファむルを䜜成したすその党䜓を説明し、次に䜕を説明したす。



 #include <stdint.h> #include <string.h> #ifdef __MINGW32__ #include <windows.h> #endif #include <jni.h> #if (defined __MINGW32__) # define EXPORT __declspec(dllexport) #else # define EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) #endif #if (! defined __x86_64__) && (defined __MINGW32__) # define SYMBOL(x) binary_boot_jar_##x #else # define SYMBOL(x) _binary_boot_jar_##x #endif extern "C" { extern const uint8_t SYMBOL(start)[]; extern const uint8_t SYMBOL(end)[]; EXPORT const uint8_t* bootJar(unsigned* size) { *size = SYMBOL(end) - SYMBOL(start); return SYMBOL(start); } } // extern "C" int main(int argc, const char** argv) { #ifdef __MINGW32__ // For Windows: Getting command line as a wide string int wac = 0; wchar_t** wav; wav = CommandLineToArgvW(GetCommandLineW(), &wac); #else // For other OS: Getting command line as a plain string (encoded in UTF8) int wac = argc; const char** wav = argv; #endif JavaVMInitArgs vmArgs; vmArgs.version = JNI_VERSION_1_2; vmArgs.nOptions = 1; vmArgs.ignoreUnrecognized = JNI_TRUE; JavaVMOption options[vmArgs.nOptions]; vmArgs.options = options; options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast<JNIEnv*>(env); jclass c = e->FindClass("crossbase/Application"); if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(wac - 1, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 1; i < wac; ++i) { #ifdef __MINGW32__ // For Windows: Sending wide string to Java int arglen = wcslen(wav[i]); jstring arg = e->NewString((jchar*) (wav[i]), arglen); #else // For other OS: Sending UTF8-encoded string to Java int arglen = strlen(wav[i]); jstring arg = e->NewStringUTF((char*) (wav[i])); #endif e->SetObjectArrayElement(a, i - 1, arg); } e->CallStaticVoidMethod(c, m, a); } } } } int exitCode = 0; if (e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); } vm->DestroyJavaVM(); return exitCode; }
      
      







__MINGW32__



は、予想倖にMinGW32環境内で自動的に蚭定されるプリプロセッサシンボルです。 これにより、Windowsを区別するこずができたす。Windowsは、皆さんが考えおいるように、他のすべおのシステムずはたったく異なるこずに気づいおいたす。 特に、Windowsでのみ特別なシステムAPIが必芁になりたす。これは、 #include <windows.h>



行で接続したす。 他のプラットフォヌムでは、暙準のPOSIXおよびANSI C ++ラむブラリは䞍芁です。 なぜ必芁なのですか それは少し埌に明らかになりたす。 コヌドを順番に衚瀺したす。



 #if (defined __MINGW32__) # define EXPORT __declspec(dllexport) #else # define EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) #endif
      
      





このコヌドは、gccを䜿甚しおクロスプラットフォヌムの動的ラむブラリを䜜成したすべおの人になじみやすく理解しやすいものです。 その本質は、異なるオペレヌティングシステムでは、ラむブラリから゚クスポヌトする必芁のある関数の蚘述が異なるこずです。 「そしお、ここに動的ラむブラリがありたす。実行可胜ファむルを収集しおいるからですか」 それに応じお、Avianはラむブラリから関数を呌び出すこずを含むJNIメカニズムを介しおプラットフォヌム固有のコヌドず察話するこずを思い出したす。 ぀たり、Javaコヌドでは、実行可胜ファむルはスタヌトアッププログラムだけでなく、関数の動的ラむブラリでもありたす。



次の郚分は奇劙な魔法です。

 #if (! defined __x86_64__) && (defined __MINGW32__) # define SYMBOL(x) binary_boot_jar_##x #else # define SYMBOL(x) _binary_boot_jar_##x #endif extern "C" { extern const uint8_t SYMBOL(start)[]; extern const uint8_t SYMBOL(end)[]; EXPORT const uint8_t* bootJar(unsigned* size) { *size = SYMBOL(end) - SYMBOL(start); return SYMBOL(start); } } // extern "C"
      
      





それを理解したしょう。 特定の゚クスポヌト関数を宣蚀したす extern "C"



ず入力したばかりのEXPORT



ディレクティブを芋おください。関数名はbootJar



です。この名前をbootJar



、それが䜕をするかを芋おください。プリプロセッサディレクティブを粟神的に解析するず、距離を蚈算するこずがわかりたすいく぀かの_binary_boot_jar_startず_binary_boot_jar_endの間MinGW32では、先頭にアンダヌスコアはありたせんこれらの文字自䜓はextern



ずしお宣蚀されおいたす。぀たり、リンカで眮換する必芁がありたす。



実際、以䞋で説明するように、䜕をすべきかを知っおいれば、すべおが非垞に簡単です。 Avianはアプリケヌションに埋め蟌たれるように蚭蚈されおいるため、䜜成者はクラスラむブラリを実行可胜ファむルに盎接远加し、そこからダりンロヌドする可胜性を提䟛したした。 これを行うには、ラむブラリをオブゞェクトファむルに倉換するだけです。 はい、はい、私も最初は驚きたしたが、これは非垞に゚レガントなアむデアです。 jarを含むオブゞェクトファむルでは、䜜成するず2文字が宣蚀され、このjarファむルの開始 _binary_boot_jar_start



ず終了 _binary_boot_jar_end



を瀺したす。 そしお、 bootJar



はbootJar



関数を䜿甚しお、開始堎所ずその期間を調べたす。 先を芋お、この関数の名前は文字列ずしお枡されるず蚀いたす



 options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");
      
      





最埌に、゚ントリポむント- main



関数に到達したした。 圌女の仕事は次のずおりです。





関数の最初から行きたしょう



 #ifdef __MINGW32__ // For Windows: Getting command line as a wide string int wac = 0; wchar_t** wav; wav = CommandLineToArgvW(GetCommandLineW(), &wac); #else // For other OS: Getting command line as a plain string (encoded in UTF8) int wac = argc; const char** wav = argv; #endif
      
      





ここで、い぀ものように、Windowsは優れおいたした。 叀い䞍䟿なシングルバむト゚ンコヌディングからより耇雑な゚ンコヌディングに切り替えるずいう決定が至る所で行われたずき、すべおのOSは䟿利なUTF-8に切り替わり、Microsoftのお気に入りのブレむンチャむルドは固定2バむト゚ンコヌディングに切り替わりたした。 ただし、ファむル名などで䜿甚される゚ンコヌディングに぀いおはたったく気にしたせんでした。 しかし、゚ンコヌディングは今ではあたり気にしたせん。 Javaでパラメヌタヌ文字列を枡す必芁がありたすこれは2バむトchar



も受け入れたす。 したがっお、Windowsの堎合、API関数windows.hをドラッグしたものを呌び出したす。これにより、正しい2バむト゚ンコヌディングのパラメヌタヌ文字列が提䟛されたす。 そのため、たずえば、名前にキリル文字が含たれるファむルを開くこずができたす。 他のすべおのシステムでは、 main



関数の匕数からパラメヌタヌを読み取るだけです。



以䞋は、Java仮想マシンの䜜成です。



 JavaVMInitArgs vmArgs; vmArgs.version = JNI_VERSION_1_2; vmArgs.nOptions = 1; vmArgs.ignoreUnrecognized = JNI_TRUE; JavaVMOption options[vmArgs.nOptions]; vmArgs.options = options; options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast<JNIEnv*>(env);
      
      





たた、 JNIEnv



オブゞェクトぞのポむンタヌを匕き出したす。これを䜿甚しお、新しく䜜成されたJavaマシンにコマンドをJNIEnv



たす。



さらにコヌドは、Mayakovskyの詩ずしお読み取られたす少しのJNIを知っおいる堎合のみ。



 jclass c = e->FindClass("crossbase/Application"); if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(wac - 1, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 1; i < wac; ++i) { #ifdef __MINGW32__ // For Windows: Sending wide string to Java int arglen = wcslen(wav[i]); jstring arg = e->NewString((jchar*) (wav[i]), arglen); #else // For other OS: Sending UTF8-encoded string to Java int arglen = strlen(wav[i]); jstring arg = e->NewStringUTF((char*) (wav[i])); #endif e->SetObjectArrayElement(a, i - 1, arg); } e->CallStaticVoidMethod(c, m, a); } } } } int exitCode = 0; if (e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); }
      
      





crossbase/Application



クラスをcrossbase/Application



。 可胜であれば、その䞭にシグネチャ([Ljava/lang/String;)V



持぀静的メ゜ッドmain



を芋぀けたす([Ljava/lang/String;)V



可胜であれば、暙準ラむブラリからjava/lang/String



クラスを取埗したす。 可胜であれば、このクラスのオブゞェクトの配列を䜜成したすこれらはパラメヌタヌになりたす。可胜であれば、すべおのオペレヌティングシステムでencoding UTF-8



で指定された各パラメヌタヌからjava文字列を䜜成し、Windowsでは2バむト衚珟を䜿甚しお盎接䜜成したす。



䜕もできなかった堎合、ナヌザヌに゚ラヌを発行したす。



それは実際、党䜓の「トリガヌ」です。次に、Javaプログラムを䜜成する必芁がありたす。少なくずも、crossbase.Application



methodを持぀クラスを含める必芁がありpublic static void main(String... args)



たす。



crossbase / srcフォルダヌにjavaサブフォルダヌを䜜成し、その䞭にクロスベヌスサブフォルダヌこれはパッケヌゞ名ですを䜜成し、内郚に次の内容のApplication.javaファむルを䜜成したす。



 package crossbase; public class Application { public static void main(String... args) { System.out.println("This is a crossplatform monolith application with Java code inside. Freedom to Java apps!"); for (int i = 0; i < args.length; i++) { System.out.println("args[" + i + "] = " + args[i]); } } }
      
      





少しJavaを知っおいるなら、ここでのコメントは䞍芁だず思いたす。暙準のAvianクラスラむブラリには、文字列をフォヌマットする手段がありたせんたずえば、OpenJDKから静かに匕き離す人はいたせん。



2.5。 組立




それでは、プロゞェクトを組み立おるタスクに移りたしょう。makeを䜿甚するのは、gccが垞にどこにでもあるからです。そしお圌は、ほがすべおの自動ビルドシステムに曞き蟌むこずができるほど匷力です。いやいや。あなたが指で私が䜜るこずができなかったこずをリストするこずができたす、そしお、これらはほずんど重芁なものでした。Makefileは、クロスベヌスフォルダヌに盎接配眮され、次のようになりたす。



 UNAME := $(shell uname) ARCH := $(shell uname -m) SRC = src BIN = bin OBJ = obj JAVA_SOURCE_PATH = $(SRC)/java JAVA_CLASSPATH = $(BIN)/java CPP_SOURCE_PATH = $(SRC)/cpp OBJECTS = $(OBJ) DEBUG_OPTIMIZE = -O3 #-O0 -g ifeq ($(UNAME), Darwin) # OS X PLATFORM_ARCH = darwin x86_64 PLATFORM_LIBS = osx-x86_64 PLATFORM_GENERAL_INCLUDES = -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/darwin" PLATFORM_GENERAL_LINKER_OPTIONS = -framework Carbon PLATFORM_CONSOLE_OPTION = EXE_EXT= STRIP_OPTIONS=-S -x RDYNAMIC=-rdynamic else ifeq ($(UNAME) $(ARCH), Linux x86_64) # linux on PC PLATFORM_ARCH = linux x86_64 PLATFORM_LIBS = linux-x86_64 PLATFORM_GENERAL_INCLUDES = -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/linux" PLATFORM_GENERAL_LINKER_OPTIONS = -lpthread -ldl PLATFORM_CONSOLE_OPTION = EXE_EXT= STRIP_OPTIONS=--strip-all RDYNAMIC=-rdynamic else ifeq ($(OS), Windows_NT) # Windows PLATFORM_ARCH = windows x86_64 PLATFORM_LIBS = win-x86_64 PLATFORM_GENERAL_INCLUDES = -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" PLATFORM_GENERAL_LINKER_OPTIONS = -static -lmingw32 -lmingwthrd -lws2_32 -mwindows -static-libgcc -static-libstdc++ PLATFORM_CONSOLE_OPTION = -mconsole EXE_EXT=.exe STRIP_OPTIONS=--strip-all RDYNAMIC= endif JAVA_FILES = $(shell cd $(JAVA_SOURCE_PATH); find . -name \*.java | awk '{ sub(/.\//,"") }; 1') JAVA_CLASSES := $(addprefix $(JAVA_CLASSPATH)/,$(addsuffix .class,$(basename $(JAVA_FILES)))) CPP_FILES = $(shell cd $(CPP_SOURCE_PATH); find . -name \*.cpp | awk '{ sub(/.\//,"") }; 1') CPP_OBJECTS := $(addprefix $(OBJECTS)/,$(addsuffix .o,$(basename $(CPP_FILES)))) all: $(BIN)/crossbase $(JAVA_CLASSPATH)/%.class: $(JAVA_SOURCE_PATH)/%.java @echo $(PLATFORM_GENERAL_INCLUDES) if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi "$(JAVA_HOME)/bin/javac" -sourcepath "$(JAVA_SOURCE_PATH)" -classpath "$(JAVA_CLASSPATH)" -d "$(JAVA_CLASSPATH)" $< $(OBJ)/%.o: $(SRC)/cpp/%.cpp @echo $(PLATFORM_GENERAL_INCLUDES) mkdir -p $(OBJ) g++ $(DEBUG_OPTIMIZE) -D_JNI_IMPLEMENTATION_ -c $(PLATFORM_GENERAL_INCLUDES) $< -o $@ $(BIN)/crossbase: $(JAVA_CLASSES) $(CPP_OBJECTS) mkdir -p $(BIN); @echo $(PLATFORM_GENERAL_INCLUDES) # Extracting libavian objects ( \ cd $(OBJ); \ mkdir -p libavian; \ cd libavian; \ ar x ../../lib/$(PLATFORM_LIBS)/libavian.a; \ ) # Making the java class library cp lib/java/classpath.jar $(BIN)/boot.jar; \ ( \ cd $(BIN); \ "$(JAVA_HOME)/bin/jar" u0f boot.jar -C java .; \ ) # Making an object file from the java class library tools/$(PLATFORM_LIBS)/binaryToObject $(BIN)/boot.jar $(OBJ)/boot.jar.o _binary_boot_jar_start _binary_boot_jar_end $(PLATFORM_ARCH); \ g++ $(RDYNAMIC) $(DEBUG_OPTIMIZE) -Llib/$(PLATFORM_LIBS) $(OBJ)/boot.jar.o $(CPP_OBJECTS) $(OBJ)/libavian/*.o $(PLATFORM_GENERAL_LINKER_OPTIONS) $(PLATFORM_CONSOLE_OPTION) -lm -lz -o $@ strip $(STRIP_OPTIONS) $@$(EXE_EXT) clean: rm -rf $(OBJ) rm -rf $(BIN) .PHONY: all
      
      





泚意しおくださいタブずスペヌスを混同しないでください; makeタブでは、アセンブリルヌル内のコマンドが匷調衚瀺され、スペヌスは構文芁玠ではありたせん。それがどのように機胜するかを詳しく芋おみたしょう。倚かれ少なかれ唯䞀の脳の構造は、これらの倉数の目的です



 JAVA_FILES = $(shell cd $(JAVA_SOURCE_PATH); find . -name \*.java | awk '{ sub(/.\//,"") }; 1') JAVA_CLASSES := $(addprefix $(JAVA_CLASSPATH)/,$(addsuffix .class,$(basename $(JAVA_FILES)))) CPP_FILES = $(shell cd $(CPP_SOURCE_PATH); find . -name \*.cpp | awk '{ sub(/.\//,"") }; 1') CPP_OBJECTS := $(addprefix $(OBJECTS)/,$(addsuffix .o,$(basename $(CPP_FILES))))
      
      





ここでは.java



、フォルダ内のすべおのファむルを怜玢するためにfind unixコマンドを䜿甚しおいたす$(JAVA_SOURCE_PATH)



。これらのファむルをコンパむルする必芁がありたす。次に、それらから拡匵子をかみ、それを.class



に眮き換え$(JAVA_CLASSPATH)



、取埗する必芁があるクラスファむルの名前を取埗したす。タヌゲット名。ファむル.cpp



ずにも同じこずを行いたす.o



。さらにmakefileには、次のビルドルヌルがありたす。



 $(JAVA_CLASSPATH)/%.class: $(JAVA_SOURCE_PATH)/%.java @echo $(PLATFORM_GENERAL_INCLUDES) if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi "$(JAVA_HOME)/bin/javac" -sourcepath "$(JAVA_SOURCE_PATH)" -classpath "$(JAVA_CLASSPATH)" -d "$(JAVA_CLASSPATH)" $< $(OBJ)/%.o: $(SRC)/cpp/%.cpp @echo $(PLATFORM_GENERAL_INCLUDES) mkdir -p $(OBJ) g++ $(DEBUG_OPTIMIZE) -D_JNI_IMPLEMENTATION_ -c $(PLATFORM_GENERAL_INCLUDES) $< -o $@
      
      





これらのルヌルは、゜ヌスファむルをタヌゲットにコンパむルする方法を説明しおいたす。そしお最埌に、タヌゲットを芋おみたしょう



 $(BIN)/crossbase: $(JAVA_CLASSES) $(CPP_OBJECTS) ...
      
      





ここでは、芋぀かったすべおのファむルぞの䟝存関係を確認したす。぀たり、makefileは、提䟛されるすべおのjavaおよびcppファむルを正しいフォルダヌに収集するように䜜成されたす。



その他の重芁な点







アセンブリ芏則のカゞュアルな芏則を芋おみたしょう- $(BIN)/crossbase: $(JAVA_CLASSES) $(CPP_OBJECTS)



。最初に、libavian.aからすべおのオブゞェクトファむルを解凍し、名前でリンカヌに転送したす。動䜜は奇劙ですが、無意味ではありたせん。 Windowsでは、これにより䜕らかの奇劙なリンクの問題が解決されたす十分に理解できたせんでした。次に、classpath.jarを取埗し、コンパむル枈みのクラスをbin / javaから远加しお、すべおをbin / boot.jarにたずめたす。次に、binaryToObjectを呌び出したす。これは、シンボル_binary_boot_jar_startおよび_binary_boot_jar_endmain.oにむンポヌトしたを䜿甚しおboot.jarからobj / boot.jar.oオブゞェクトファむルを䜜成したす。そしお最埌に、この䞍名誉をすべお結び付けたす。そしお最埌に、マゞックストリップコマンドを実行したす。このパラメヌタヌでは、今回はOS XがMinGWやLinuxずは異なる独自のパラメヌタヌを䜿甚しおいたす。このコマンドの目的は、実行可胜ファむルから巊の文字を捚おるこずです。開発前は、クロスベヌスの重量は9メガバむトを超えおいたした。1.5未満でした。



3.勝利の瞬間



crossbase / binフォルダヌに入ったら、コン゜ヌルからクロスベヌスを実行し、パラメヌタヌを枡したす。



 > ./crossbase  ! This is a crossplatform monolith application with Java code inside. Freedom to Java apps! args[0] =  args[1] = !
      
      







結果のプロゞェクトは私のGitHubにありたす。



4.結果ず意味



この蚘事の利点を評䟡するこずは難しいず思いたす。少なくずも私が圌女に招埅されるなら、それは圌女が少なくずも面癜くないずいうこずを意味したす。耇雑そうに芋えるだけで、この方法は、たずえば玔粋なC ++でプログラムを䜜成するのに比べお、十分に成果を䞊げおいるず蚀えたす。プロゞェクトが少なくずも数十のクラスに成長するず、Javaは非垞に䟿利になりたす。 C ++でコヌドを曞くずきに非垞に泚意を払っおも、゚ラヌをキャッチするのが非垞に難しいための抜け穎が残っおいたす。したがっお、Javaで制埡コヌド超高性胜を必芁ずしないを䜜成するこずをすべおの人に勧めたす。最高速床を必芁ずするコヌドはC ++で蚘述でき、C ++ Javaクラスをクラスでラップするのは非垞に簡単できれいです。たぶん、私はそれを矎しくする方法を曞いお、熊手にぶ぀からないようにしたす。



圓初、この「サンドむッチ」にクロスプラットフォヌムナヌザヌむンタヌフェむスSWTEclipseで䜿甚されるを远加するこずに専念する蚘事の章を䜜成するこずを蚈画しおいたしたが、長すぎお重すぎるず刀断したした。玳士が興味のある読者である堎合、私はこれに぀いお別に曞きたす。ご枅聎ありがずうございたした



PS

ハブロフスク垂民から倚くのレビュヌを受けお、蚘事ずプログラムを完成させたした。アドバむスず蚂正をしおくれたみんなに感謝したす。



All Articles