개발도구 없이 Java 프로그램을 직접 컴파일하고 실행하기
.
JAVA_TIL(20200829)
- study program : youtube 생활코딩 채널 ‘JAVA1’
[실습목표]
-
이클립스와 같은 개발도구를 사용하지 않고 자바로 만든 프로그램을 컴파일하고 실행해보자.
-
어떤 컴퓨터에서든, 어떤 환경에서든지 자바만 있다면 이클립스 같은 개발도구 없이 자바 프로그램을 실행할 수 있다.
-
자바 확장자가 붙은 소스코드를 클래스 확장자가 붙은 실행파일로 컴파일하고 클래스 확장자가 붙은 파일을 실행해보자. 거기에 추가로 실행할때 입력값도 줘보자. 입력값에 따라 프로그램이 다르게 동작해보는 것을 확인해보자.
실습 1) Program.java 파일을 Program.class로 컴파일해서 실행해보려고 한다.
실습 2) OkJavaGoinHome.java라는 라이브러리가 포함된 소스코드 파일을 class 확장자로 컴파일하고, run 해본다.
실습 3) 마찬가지로 OkJavaGoinHomeInput.java 파일을 class 확장자로 컴파일하고, run 해보는데 input을 어떻게 처리할지 이것도 해볼 것이다.
[실습내용]
- 실습환경
Amazonlinux AMI EC2
- 사전준비
실습파일을 해당 ec2에 업로드, sudo yum update -y
로 패키지 업데이트후 자바설치
# tree 패키지 설치
[ec2-user@ip-10-1-10-254 practice]$ sudo yum install tree -y
[ec2-user@ip-10-1-10-254 practice]$ ls
Data_and_operation HelloWorldGUI MyApp
HelloWorld HelloWorld_IOT Programming
# 자바 설치
[ec2-user@ip-10-1-10-254 practice]$ sudo yum install -y java-1.8.0-openjdk-devel.x86_64
[ec2-user@ip-10-1-10-254 practice]$ java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)
자바를 컴파일하기 위해서는 javac라는 것을 이용해서 컴파일할 수 있다.
[ec2-user@ip-10-1-10-254 practice]$ javac
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라는 것은 어디에 있는가 아래의 명령어로 확인할 수 있다.
# 자바의 경로
[ec2-user@ip-10-1-10-254 practice]$ readlink -f $(which java)
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.252.b09-2.amzn2.0.1.x86_64/jre/bin/java
# javac의 경로
[ec2-user@ip-10-1-10-254 practice]$ readlink -f $(which javac)
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.252.b09-2.amzn2.0.1.x86_64/bin/javac
내가 java라고 명령을 내렸을때 저 명령이 현재 어디에 있건간에 실행되는 이유는 뭐때문일까. 바로 path라고 하는 환경변수 때문이다.
java라고 명령을 내리면 운영체제는 현재 디렉토리에 자바가 있는지 확인하고, 없으면 환경변수 경로를 찾아서 자바라는 파일이 있으면 그거를 실행하게 된다. 만약에 못찾는다면 Error를 발생시킬것이다.
- 환경변수 확인방법
[ec2-user@ip-10-1-10-254 practice]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/ec2-user/.local/bin:/home/ec2-user/bin
- 환경변수 설정법
.bash_profile 마지막줄 아래에 경로를 추가해주면 된다.
[ec2-user@ip-10-1-10-254 practice]$ vim ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
실습 1) Program.java 파일을 Program.class로 컴파일해서 실행해보자.
- Program.java
public class Program {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
System.out.println(3);
}
}
ec2에서 아래와 같이 명령어를 실행하여 실습해본다.
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java InstanceApp.java OkJavaGoInHomeInput.java OkJavaGoInHome.java org Program.java
[ec2-user@ip-10-1-10-254 Programming]$ javac Program.java
# javac 명령어로 Program.class가 생성되었다.
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java InstanceApp.java OkJavaGoInHomeInput.java OkJavaGoInHome.java org Program.class Program.java
# 자바는 현재 디렉토리에 Program.class 파일이 있는지를 찾아보고 있다면 그거를 실행시킨다.
[ec2-user@ip-10-1-10-254 Programming]$ java Program
1
2
3
# Program.class을 실행하라 그러면 Program.class에서 클래스파일의 이름을 찾는다 다시말해서 소스코드 안에서 Program class를 찾는다.
# 그 다음에 main을 찾는다 그 다음에 main 중괄호 안에 있는 코드를 순차적으로 실행하고 종료한다.
[ec2-user@ip-10-1-10-254 Programming]$ cat Program.java
public class Program {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
System.out.println(3);
}
}
실습 2) OkJavaGoinHome.java라는 라이브러리가 포함된 소스코드 파일을 class 확장자로 컴파일하고, run 해본다.
- OkJavaGoinHome.java
## OkJavaGoinHome.java 코드에서 Elevator, Security, Lightning 객체는 아래와 같이
## 외부의 패키지에서 import 한 것들이다.
import org.opentutorials.iot.Elevator;
import org.opentutorials.iot.Lighting;
import org.opentutorials.iot.Security;
public class OkJavaGoInHome {
public static void main(String[] args) {
String id = "JAVA APT 507";
// Elevator call
Elevator myElevator = new Elevator(id);
myElevator.callForUp(1);
// Security off
Security mySecurity = new Security(id);
mySecurity.off();
// Light on
Lighting hallLamp = new Lighting(id+" / Hall Lamp");
hallLamp.on();
Lighting floorLamp = new Lighting(id+" / floorLamp");
floorLamp.on();
}
}
아래와 같이 iot 폴더안에 있는 파일들을 패키지라고 부른다. 작은 프로그램들이 모여있는 패키지인 것이다.
여기에 Elevator.java라는 파일이 있고, 이 파일을 컴파일하면 Elevator.class가 생성된다. 이 Elevator.class를 로딩하는 코드가 위에서 import org.opentutorials.iot.Elevator;
이다. Lightning과 Security도 마찬가지이다.
그래서 이런 패키지들이 임포트되었기 때문에 Elevator,Lightning,Security 메서드를 아래의 파일목록에서 각각의 class로 부터 참조해서 쓸 수 있게 된다.
[ec2-user@ip-10-1-10-254 iot]$ pwd
/home/ec2-user/practice/Programming/org/opentutorials/iot
[ec2-user@ip-10-1-10-254 iot]$ ll
total 72
-rw-rw-r-- 1 ec2-user ec2-user 1290 Aug 29 05:46 Aircon.class
-rw-rw-r-- 1 ec2-user ec2-user 500 Aug 29 05:46 Aircon.java
-rw-rw-r-- 1 ec2-user ec2-user 1137 Aug 29 05:46 ColorDimmingLights.class
-rw-rw-r-- 1 ec2-user ec2-user 379 Aug 29 05:46 ColorDimmingLights.java
-rw-rw-r-- 1 ec2-user ec2-user 1002 Aug 29 05:46 DimmingLights.class
-rw-rw-r-- 1 ec2-user ec2-user 320 Aug 29 05:46 DimmingLights.java
-rw-rw-r-- 1 ec2-user ec2-user 1186 Aug 29 05:46 Elevator.class
-rw-rw-r-- 1 ec2-user ec2-user 401 Aug 29 05:46 Elevator.java
-rw-rw-r-- 1 ec2-user ec2-user 1261 Aug 29 05:46 Lighting.class
-rw-rw-r-- 1 ec2-user ec2-user 440 Aug 29 05:46 Lighting.java
-rw-rw-r-- 1 ec2-user ec2-user 146 Aug 29 05:46 OnOff.class
-rw-rw-r-- 1 ec2-user ec2-user 104 Aug 29 05:46 OnOff.java
-rw-rw-r-- 1 ec2-user ec2-user 1279 Aug 29 05:46 Refrigerator.class
-rw-rw-r-- 1 ec2-user ec2-user 493 Aug 29 05:46 Refrigerator.java
-rw-rw-r-- 1 ec2-user ec2-user 1334 Aug 29 05:46 Security.class
-rw-rw-r-- 1 ec2-user ec2-user 518 Aug 29 05:46 Security.java
-rw-rw-r-- 1 ec2-user ec2-user 980 Aug 29 05:46 Speaker.class
-rw-rw-r-- 1 ec2-user ec2-user 245 Aug 29 05:46 Speaker.java
일단 실습을 위해서 /home/ec2-user/practice/Programming/org/opentutorials/iot
에서 class 파일을 모두 삭제해준다.
그리고 javac로 OkJavaGoInHome.java를 컴파일 해본다. 그러면 class 파일이 생성될 것이고, iot 패키지 폴더 아래에 class 파일들이 쭉 생성된 것을 확인할 수 있다.
OkJavaGoInHome.java는 내부적으로 이 iot 패키지 안에 있는 여러 파일들을 전부 필요로 하기 때문에 자바 컴파일러가 패키지 안에 있는 .java들도 컴파일을 해준것이다.
[ec2-user@ip-10-1-10-254 iot]$ ls
Aircon.class DimmingLights.class Lighting.class Refrigerator.class Speaker.class
Aircon.java DimmingLights.java Lighting.java Refrigerator.java Speaker.java
ColorDimmingLights.class Elevator.class OnOff.class Security.class
ColorDimmingLights.java Elevator.java OnOff.java Security.java
[ec2-user@ip-10-1-10-254 iot]$ rm *.class
[ec2-user@ip-10-1-10-254 iot]$ ls
Aircon.java DimmingLights.java Lighting.java Refrigerator.java Speaker.java
ColorDimmingLights.java Elevator.java OnOff.java Security.java
[ec2-user@ip-10-1-10-254 iot]$ cd /home/ec2-user/practice/Programming
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java InstanceApp.java OkJavaGoInHomeInput.java OkJavaGoInHome.java org Program.class Program.java
[ec2-user@ip-10-1-10-254 Programming]$ javac OkJavaGoInHome.java
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java OkJavaGoInHome.class OkJavaGoInHome.java Program.class
InstanceApp.java OkJavaGoInHomeInput.java org Program.java
[ec2-user@ip-10-1-10-254 Programming]$ cd /home/ec2-user/practice/Programming/org/opentutorials/iot
[ec2-user@ip-10-1-10-254 iot]$ ls
Aircon.java Elevator.class Lighting.java Refrigerator.java Speaker.java
ColorDimmingLights.java Elevator.java OnOff.class Security.class
DimmingLights.java Lighting.class OnOff.java Security.java
위와 같이 실습을 해보고 iot 폴더안에 class 파일들을 또 모두 삭제해준다.
그리고 Programming 폴더에 lib이라는 폴더를 하나 만들고 org 폴더를 몽땅 lib 안으로 이동시켜준다.
(org 폴더를 lib 폴더 안에 넣어서 OkJavaGoInHome.java와 org 폴더가 같은 디렉토리선에 있지 않도록 해준 것이다.)
그런 다음에 다시 javac OkJavaGoInHome.java
명령을 해보자.
[ec2-user@ip-10-1-10-254 iot]$ rm *.class
[ec2-user@ip-10-1-10-254 iot]$ ls
Aircon.java DimmingLights.java Lighting.java Refrigerator.java Speaker.java
ColorDimmingLights.java Elevator.java OnOff.java Security.java
[ec2-user@ip-10-1-10-254 iot]$ cd /home/ec2-user/practice/Programming
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java OkJavaGoInHome.class OkJavaGoInHome.java Program.class
InstanceApp.java OkJavaGoInHomeInput.java org Program.java
[ec2-user@ip-10-1-10-254 Programming]$ mkdir lib
[ec2-user@ip-10-1-10-254 Programming]$ mv org lib/org
[ec2-user@ip-10-1-10-254 Programming]$ ls
ClassApp.java lib OkJavaGoInHomeInput.java Program.class
InstanceApp.java OkJavaGoInHome.class OkJavaGoInHome.java Program.java
[ec2-user@ip-10-1-10-254 Programming]$ cd lib
[ec2-user@ip-10-1-10-254 lib]$ ls
org
[ec2-user@ip-10-1-10-254 lib]$ cd ..
# 우리가 컴파일하고 있는 OkJavaGoInHome.java와 org 패키지가 같은 디렉토리에 있지 않기 때문에
# 각각의 패키지들이 존재하지 않는다고 Error가 발생한다.
[ec2-user@ip-10-1-10-254 Programming]$ javac OkJavaGoInHome.java
OkJavaGoInHome.java:1: error: package org.opentutorials.iot does not exist
import org.opentutorials.iot.Elevator;
^
OkJavaGoInHome.java:2: error: package org.opentutorials.iot does not exist
import org.opentutorials.iot.Lighting;
^
OkJavaGoInHome.java:3: error: package org.opentutorials.iot does not exist
import org.opentutorials.iot.Security;
^
OkJavaGoInHome.java:12: error: cannot find symbol
Elevator myElevator = new Elevator(id);
^
symbol: class Elevator
location: class OkJavaGoInHome
OkJavaGoInHome.java:12: error: cannot find symbol
Elevator myElevator = new Elevator(id);
^
symbol: class Elevator
location: class OkJavaGoInHome
OkJavaGoInHome.java:16: error: cannot find symbol
Security mySecurity = new Security(id);
^
symbol: class Security
location: class OkJavaGoInHome
OkJavaGoInHome.java:16: error: cannot find symbol
Security mySecurity = new Security(id);
^
symbol: class Security
location: class OkJavaGoInHome
OkJavaGoInHome.java:20: error: cannot find symbol
Lighting hallLamp = new Lighting(id+" / Hall Lamp");
^
symbol: class Lighting
location: class OkJavaGoInHome
OkJavaGoInHome.java:20: error: cannot find symbol
Lighting hallLamp = new Lighting(id+" / Hall Lamp");
^
symbol: class Lighting
location: class OkJavaGoInHome
OkJavaGoInHome.java:23: error: cannot find symbol
Lighting floorLamp = new Lighting(id+" / floorLamp");
^
symbol: class Lighting
location: class OkJavaGoInHome
OkJavaGoInHome.java:23: error: cannot find symbol
Lighting floorLamp = new Lighting(id+" / floorLamp");
^
symbol: class Lighting
location: class OkJavaGoInHome
11 errors
이럴때 사용하는 것이 javac에서 --class-path <path>
또는 --cp <path>
옵션이다.
OkJavaGoInHome.java가 컴파일되기 위해 필요한 class파일이 어디에 있는지를 지정해 줄 수 있는 것이다.
이 옵션으로 다시한번 javac로 컴파일해보면 컴파일은 잘 되는 것을 확인할 수 있다.
컴파일을 했으니까 java로 실행을 해보는데 실행을 하면 아래와 같이 Error가 날 것이다.
이것도 마찬가지로 OkJavaGoInHome.class를 실행하는데 필요한 패키지들이 동일한 디렉토리 선상에 위치하지 않고 있기 때문이다.
[ec2-user@ip-10-1-10-254 Programming]$ javac -cp ".:lib" OkJavaGoInHome.java
[ec2-user@ip-10-1-10-254 Programming]$ java OkJavaGoInHome
Exception in thread "main" java.lang.NoClassDefFoundError: org/opentutorials/iot/Elevator
at OkJavaGoInHome.main(OkJavaGoInHome.java:12)
Caused by: java.lang.ClassNotFoundException: org.opentutorials.iot.Elevator
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 1 more
이것도 그러면 경로를 지정해서 실행할 수 있도록 아래와 같이 명령을 해주면 될텐데 또 error가 난다.
자바를 실행시키는 디렉토리에 있는 OkJavaGoInHome.class 파일을 찾도록 약속되어 있는데 명시적으로 lib이라고 명시하면 lib에서만 찾기 때문이다.
그래서 그 아래에 있는 명령어와 같이 실행하면 정상적으로 프로그램이 실행되는 것을 확인할 수 있다.
[ec2-user@ip-10-1-10-254 Programming]$ java -cp "lib" OkJavaGoInHome
Error: Could not find or load main class OkJavaGoInHome
# 현재 디렉토리에서 OkJavaGoInHome.class를 열어서 거기에 있는 main안에 있는걸
# 실행시키다가 elevator 코드가 있으면 그거를 lib 밑에 있는 패키지를 참조할 수 있도록 해준것이다.
# 이렇게 다른사람이 사용할 수 있도록 정리정돈된 프로그램들을 라이브러리라고 부른다.
[ec2-user@ip-10-1-10-254 Programming]$ java -cp ".:lib" OkJavaGoInHome
JAVA APT 507 → Elevator callForUp stopFloor : 1
JAVA APT 507 → Security off
JAVA APT 507 / Hall Lamp → Lighting on
JAVA APT 507 / floorLamp → Lighting on
그러면 다시 org 파일을 원복하고, iot 폴더 밑에 class 파일들을 다시 삭제해보자
[ec2-user@ip-10-1-10-254 Programming]$ cd lib
[ec2-user@ip-10-1-10-254 lib]$ mv org /home/ec2-user/practice/Programming/
[ec2-user@ip-10-1-10-254 lib]$ cd ..
[ec2-user@ip-10-1-10-254 Programming]$ rm -rf lib
[ec2-user@ip-10-1-10-254 Programming]$ cd /home/ec2-user/practice/Programming/org/opentutorials/iot
[ec2-user@ip-10-1-10-254 iot]$ rm *.class
[ec2-user@ip-10-1-10-254 iot]$ cd /home/ec2-user/practice/Programming
[ec2-user@ip-10-1-10-254 Programming]$ tree .
.
├── ClassApp.java
├── InstanceApp.java
├── OkJavaGoInHome.class
├── OkJavaGoInHomeInput.java
├── OkJavaGoInHome.java
├── org
│ └── opentutorials
│ └── iot
│ ├── Aircon.java
│ ├── ColorDimmingLights.java
│ ├── DimmingLights.java
│ ├── Elevator.java
│ ├── Lighting.java
│ ├── OnOff.java
│ ├── Refrigerator.java
│ ├── Security.java
│ └── Speaker.java
├── Program.class
└── Program.java
3 directories, 16 files
실습 3) OkJavaGoinHomeInput.java 파일을 class 확장자로 컴파일하고, run 해보는데 input을 주는 것도 해보자.
- OkJavaGoinHomeInput.java
import javax.swing.JOptionPane;
import org.opentutorials.iot.DimmingLights;
import org.opentutorials.iot.Elevator;
import org.opentutorials.iot.Lighting;
import org.opentutorials.iot.Security;
public class OkJavaGoInHomeInput {
// paramter, 매개변수
public static void main(String[] args) {
String id = args[0];
String bright = args[1];
// Elevator call
Elevator myElevator = new Elevator(id);
myElevator.callForUp(1);
// Security off
Security mySecurity = new Security(id);
mySecurity.off();
// Light on
Lighting hallLamp = new Lighting(id+" / Hall Lamp");
hallLamp.on();
Lighting floorLamp = new Lighting(id+" / floorLamp");
floorLamp.on();
DimmingLights moodLamp = new DimmingLights(id+" moodLamp");
moodLamp.setBright(Double.parseDouble(bright));
moodLamp.on();
}
}
아래 명령어와 같이 OkJavaGoInHomeInput.java를 컴파일해서 실행해보자.
그러면 Error가 발생할 것이다.
[ec2-user@ip-10-1-10-254 Programming]$ javac OkJavaGoInHomeInput.java
[ec2-user@ip-10-1-10-254 Programming]$ tree .
.
├── ClassApp.java
├── InstanceApp.java
├── OkJavaGoInHome.class
├── OkJavaGoInHomeInput.class
├── OkJavaGoInHomeInput.java
├── OkJavaGoInHome.java
├── org
│ └── opentutorials
│ └── iot
│ ├── Aircon.java
│ ├── ColorDimmingLights.java
│ ├── DimmingLights.class
│ ├── DimmingLights.java
│ ├── Elevator.class
│ ├── Elevator.java
│ ├── Lighting.class
│ ├── Lighting.java
│ ├── OnOff.class
│ ├── OnOff.java
│ ├── Refrigerator.java
│ ├── Security.class
│ ├── Security.java
│ └── Speaker.java
├── Program.class
└── Program.java
3 directories, 22 files
[ec2-user@ip-10-1-10-254 Programming]$ java OkJavaGoInHomeInput
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at OkJavaGoInHomeInput.main(OkJavaGoInHomeInput.java:13)
위에 소스코드에서 String id = args[0]; 라인에서 문제가 발생했기 때문에 Error가 난것이다.
args에 입력값을 안줬기 때문에 당연히 Error가 난 것이다.
따라서 아래와 같이 arg를 추가해서 실행시키면 원하는대로 동작을 할 것이다.
[ec2-user@ip-10-1-10-254 Programming]$ java OkJavaGoInHomeInput "Seoul APT 507" "70"
Seoul APT 507 → Elevator callForUp stopFloor : 1
Seoul APT 507 → Security off
Seoul APT 507 / Hall Lamp → Lighting on
Seoul APT 507 / floorLamp → Lighting on
Seoul APT 507 moodLamp → DimmingLights bright : 70.0
Seoul APT 507 moodLamp → Lighting on
[ec2-user@ip-10-1-10-254 Programming]$ java OkJavaGoInHomeInput "Pusan APT 903" "50"
Pusan APT 903 → Elevator callForUp stopFloor : 1
Pusan APT 903 → Security off
Pusan APT 903 / Hall Lamp → Lighting on
Pusan APT 903 / floorLamp → Lighting on
Pusan APT 903 moodLamp → DimmingLights bright : 50.0
Pusan APT 903 moodLamp → Lighting on