فصل ششم
نحوه ی کامپایل سورس کد های جاوا با کامپایلر ( javac )
خب همانطور که در فصل های گذشته دیدیم، ابزار javac یکی از ابزار های jdk هست که برای کامپایل سورس کدهای جاوا به کار می رود. چون نرم افزار javac، رابط گرافیکی یا همان GUI ندارد بنابراین باید از طریق ترمینال ان را اجرا کنیم تا برنامه را کامپایل کنیم. اما ابتدا باید نگاهی به فلگ های (flag) ان داشته باشیم.
توجه: jdk من ورژن 1.8 هست، jdk 9 یه مقدار تفاوت کرده که بعدا توضیح میدم.
ابتدا در ترمینال دستور javac -help رو می زنیم تا ببینیم چه فلگ هایی داره
Usage: javac <options> <source files>
where possible options include:
-g Generate all debugging info
-g:none Generate no debugging info
-g:{lines,vars,source} Generate only some debugging info
-nowarn Generate no warnings
-verbose Output messages about what the compiler is doing
-deprecation Output source locations where deprecated APIs are used
-classpath <path> Specify where to find user class files and annotation processors
-cp <path> Specify where to find user class files and annotation processors
-sourcepath <path> Specify where to find input source files
-bootclasspath <path> Override location of bootstrap class files
-extdirs <dirs> Override location of installed extensions
-endorseddirs <dirs> Override location of endorsed standards path
-proc:{none,only} Control whether annotation processing and/or compilation is done.
-processor <class1>[,<class2>,<class3>...] Names of the annotation processors to run; bypasses default discovery process
-processorpath <path> Specify where to find annotation processors
-parameters Generate metadata for reflection on method parameters
-d <directory> Specify where to place generated class files
-s <directory> Specify where to place generated source files
-h <directory> Specify where to place generated native header files
-implicit:{none,class} Specify whether or not to generate class files for implicitly referenced files
-encoding <encoding> Specify character encoding used by source files
-source <release> Provide source compatibility with specified release
-target <release> Generate class files for specific VM version
-profile <profile> Check that API used is available in the specified profile
-version Version information
-help Print a synopsis of standard options
-Akey[=value] Options to pass to annotation processors
-X Print a synopsis of nonstandard options
-J<flag> Pass <flag> directly to the runtime system
-Werror Terminate compilation if warnings occur
@<filename> Read options and filenames from file
همانطور که می بینید، در خط اول، نحوه ی استفاده از کامپایلر جاوا را توضیح داده.
<javac <options> <source files
بجای <options> ما می توانیم چندین تا از فلگ های بالا رو بزاریم.
اما ۳ تا از فلگ ها برای ما خیلی مهم هستن.
۱- فلگ sourcepath-
۲- فلگ classpath-
۳- فلگ d-
فلگ sourcepath
فلگ sourcepath- همانطور که از اسمش پیداست، ادرس سورس کدهای پروژه را مشخص می کند. به عبارت دقیق تر، ادرس "پکیج روت دایرکتوری" پروژه را. و به عبارت دیگر، javac از این ادرس شروع میکنه به گشتن پکیج ها و فایل های java.
به فرض اگر تمام پکیج های پروژه داخل پوشه ی src باشند، مقدار sourcepath می شود آدرس پوشه ی src
نکته ی بسیار مهم۱: در جاوا این امکان وجود دارد که همه، (یا برخی) از پکیج های پروژه ی ما، داخل فایل jar یا حتی داخل فایل zip باشد. به عبارت دیگر ما می توانیم یک فایل zip داشته باشیم که برخی از پکیج ها و سورس کد ما (فایل های java.) داخل آن باشد. بنابراین ادرس فایل های زیپ و جار رو هم باید بدیم به sourcepath
حالا اگر پکیج های ما هر کدام در یک ادرسی باشند (فرض کنید یک پکیج در درایو F و دیگری در درایو D باشد و یک پکیج ما نیز در داخل یک فایل zip باشد)، در آن صورت، سه تا پکیج روت دایرکتوری داریم، و مقدار sourcepath میشه آدرس هر سه تای آنها ( که با علامت : از هم جدا شده اند) (در لینوکس با علامت ; از هم جدا می شوند). به عبارت دیگر، زمانی که javac بخواهد دنبال پکیج ها و سورس کدها بگردد، باید ۲ تا ادرس را جستجو کند به اضافه محتویات یک فایل zip را.
نکته ی بسیار مهم۲: زمانی که شما فلگ sourcepath رو به javac ندهید، javac مقدار sourcepath را معادل current working directory در نظر می گیرد. به عبارت دیگر، اگر شما فلگ sourcepath را به javac ندهید، javac از ادرس فعلی شروع می کند به گشتن پکیج ها و کلاس ها
فلگ classpath
فلگ classpath- نیز همانطور که از اسمش پیداست، ادرس کلاس های کامپایل شده را مشخص می کند. به عبارت دقیق تر، ادرس "پکیج روت دایرکتوری" فایل های class. را
و به عبارت دیگر، زمانی که javac بخواهد دنبال پکیج ها و فایل های کامپایل شده بگردد، از این ادرس شروع می کند به گشتن
فرض کنید کسی قبلا در جاوا کلاس Util را نوشته و آن را کامپایل کرده، و فایل Util.class را به شما داده
(هر چند که مرسوم نیست فایل کامپایل شده ی جاوا رو همینجوری بدیم به کسی، روش بهتر این هست که بزاریم داخل یک فایل jar و فایل jar رو بدیم به طرف. این فایل jar در واقع میشه همان لایببری)
ولی حالا بیاید فرض کنیم که این اتفاق افتاده و کلاس کامپایل شده (فایل Util.class) رو از دوستتون گرفتید، و ازش در پروژه استفاده کردید. حالا زمانی که بخواهید پروژه ی خودتون رو کامپایل کنید، باید ادرس "پکیج روت دایرکتوری" اون فایل class. رو، بدید به فلگ classpath
به فرض اگر کلاس Util در پکیج com.lib باشد، معنیش این هست که فایل Util.class داخل پوشه ی lib و پوشه ی lib داخل پوشه ی com هست. درسته؟
حالا اگر پوشه ی com در ادرس home/linuxgeek/ باشد، این ادرس می شود پکیج روت دایرکتوری فایل Util.class
به عبارت دیگر، زمانی که javac بخواهد دنبال پکیج com.lib و فایل Util.class بگردد، از ادرس home/linuxgeek/ شروع می کند به جستجو
نکته ی بسیار مهم۱: در جاوا این امکان وجود دارد که همه، (یا برخی) از پکیج های پروژه ی ما، داخل فایل jar یا حتی داخل فایل zip باشد. به عبارت دیگر، فایل zip می تواند حاوی پکیج ها و کلاس های کامپایل شده باشد. بنابراین آدرس فایل zip و jar رو هم باید بدیم به classpath
حالا اگر فایل های کامپایل شده ی ما، هر کدام در یک ادرسی باشند (فرض کنید یک پکیج در درایو F و دیگری در درایو D باشد و یک پکیج ما نیز در داخل یک فایل zip باشد)، در آن صورت، سه تا پکیج روت دایرکتوری داریم، و مقدار classpath میشه آدرس هر سه تای آنها ( که با علامت : از هم جدا شده اند) (در لینوکس با علامت ; از هم جدا می شوند). به عبارت دیگر، زمانی که javac بخواهد دنبال bytecode ها بگردد، باید ۲ تا ادرس را جستجو کند به اضافه محتویات یک فایل zip را.
نکته ی بسیار مهم۲: زمانی که شما فلگ classpath رو به javac ندهید، javac مقدار classpath را معادل current working directory در نظر می گیرد. به عبارت دیگر، اگر شما فلگ sourcepath را به javac ندهید، javac از ادرس فعلی شروع می کند به گشتن پکیج ها و کلاس ها (دقیقا مثل sourcepath)
فلگ d-
زمانی که javac فایل های سورس را کامپایل می کند، به طور پیش فرض، فایل بایت کد را (class.) کنار همان سورس کد ایجاد می کند. اگر بخواهیم فایل های بایت کد، به طور کلی در یک ادرس دیگر ایجاد شوند، از فلگ d- استفاده می کنیم. در این صورت، کامپایلر ابتدا پکیج های مربوطه را بصورت خودکار ساخته، و فایل های بایت کد را در پکیج های مربوط به خودشان قرار می دهد.
به عبارت دیگر، ما باید ادرس "پکیج روت دایرکتوری" مد نظر خودمان را بدهیم به فلگ d- تا کامپایلر در آن ادرس پکیج ها و بایت کد ها را بسازد
اکلیپس نیز با استفاده از فلگ d- در کنار پوشه ی src یک پوشه می سازد به نام bin و پکیج ها را داخل آن قرار می دهد (به همراه فایل های کامپایل شده)
دستور کامپایل در جاوا
تا اینجا همه چیز رو درباره javac و فلگ های اون گفتم. برای اینکه صحبت هارو جمع بندی کنم، دستور کلی کامپایل در جاوا رو در زیر می نویسم
javac -sourcepath path1;path2;file.zip;file.jar -classpath path1;path2;file.zip;file.jar path/to/Main.java
path1: ادرس پکیج روت دایرکتوری
path2: ادرس پکیج روت دایرکتوری
file.zip: فایل زیپ که می تواند حاوی پکیج ها و فایل های class. یا java. باشد.
file.jar: فایل جار که می تواند حاوی پکیج ها و فایل های class. و یا java. باشد.
path/to/Main.java: ادرس فایل Main.java
و نکته ی پایانی اینکه، زمانی که شما فقط ادرس فایل Main.java رو به کامپایلر میدید، کامپایلر به طور اتوماتیک، تمام کلاس هایی که در Main.java ایمپورت شدن رو پیدا میکنه و انها رو هم کامپایل میکنه. چجوری پیدا میکنه؟ با گشتن درون پکیج روت دایرکتوری و فایل های zip و jar