아무도 make for Java를 사용하지 않는 이유는 무엇입니까?


162

내가 본 모든 Java 프로젝트는 Maven 또는 Ant를 사용합니다. 그들은 훌륭한 도구이며 거의 모든 프로젝트에서 사용할 수 있다고 생각합니다. 그러나 이제까지 우연히 만들어 ? Java 이외의 다양한 프로젝트에 사용되며 Java를 쉽게 처리 할 수 ​​있습니다. Windows를 사용하는 경우 make.exe를 다운로드해야하지만 Ant 및 Maven에도 JDK가 제공되지 않습니다.

Java와 함께 사용할 때 make에 근본적인 결함이 있습니까? Ant와 Maven이 Java로 작성 되었기 때문입니까?


37
무언가를 움직이고 컴파일러를 호출하는 것 이상을 수행하는 경우 플랫폼 관련 내용이 처리하기가 매우 어려워집니다 make. 그리고 하나의 시스템에서만 작동하는 makefile을 갖는 것은 크로스 플랫폼 언어에 좋지 않습니다.
Joey

옆으로 Gradle은 Gant와 마찬가지로 Java 공간에서 새로운 플레이어입니다. Maven 또는 Ant는 잘못된 이분법입니다.
Michael Easter

@Michael Easter, 허위 이분법은 Maven / Ant vs. Make입니다. 내가 당신을 올바르게 읽고 있다면 진정한 이분법은 Gradle / Maven / Gant / Ant vs. Make입니다. 그러나 말하기는 어렵습니다 :)
Dan Rosenstark

답변:


192

Make와 Java의 근본적인 문제는 Make가 종속성을 지정한 전제에서 작동 한 다음 해당 종속성을 해결하기위한 규칙입니다.

기본 C에서 "main.c 파일을 main.o 파일로 변환하려면"cc main.c "를 실행하십시오.

Java로 할 수는 있지만 빠르게 배울 수 있습니다.

대부분 javac 컴파일러가 느리게 시작됩니다.

차이점은 다음과 같습니다.

javac Main.java
javac This.java
javac That.java
javac Other.java

javac Main.java This.java That.java Other.java

밤낮입니다.

수백 개의 클래스로 그것을 악화시키고, 그것은 단지 참을 수 없게됩니다.

그런 다음 Java와 디렉토리의 파일 그룹으로 구성되는 경향이 있다는 사실과 C 및 더 평평한 구조를 지향하는 다른 파일과 결합합니다. Make는 파일 계층 작업을 직접적으로 지원하지 않습니다.

또한 Make는 컬렉션 수준에서 오래된 파일을 결정하는 데 좋지 않습니다.

Ant를 사용하면 오래된 파일을 모두 요약 한 다음 한 번에 컴파일합니다. Make는 단순히 각 개별 파일에서 Java 컴파일러를 호출합니다. 이렇게하지 않으면 Make가 작업에 크게 영향을 미치지 않는다는 것을 보여줄 수있는 충분한 외부 도구가 필요합니다.

그렇기 때문에 Ant 및 Maven과 같은 대안이 등장했습니다.


6
따라서 거대한 Java 프로젝트에서 make를 사용하려면 변경된 모든 .java 파일 목록을 유지 관리하고 마지막에 javac를 호출해야합니까? 그것은 나에게 이상적이지 않습니다. 이것이 내가 지금까지 본 최고의 답변입니다.
사용자 1

32
나는 이것을 좋아한다. 본질적으로 javac가 너무 느리다는 사실을 해결하기 위해 Ant가 필요하다고 말하고 있습니다.
cmcginty

25
아니요. Javac는 사용하도록 설계된대로 사용하면 느리지 않습니다. 한 번에 하나의 파일을 컴파일하는 데 사용하면 속도가 느립니다.
Stephen C

7
@Casey javac는 너무 느리지 않습니다. JVM이 시작하기에 너무 느립니다.
Thorbjørn Ravn Andersen

7
GNU Make는 최소한 $?자동 변수 를 가지고있어 "대상보다 새로운 전제 조건"으로 확장됩니다. 레시피를 한 번만 실행하여 모든 파일 을 업데이트하는 여러 개의 대상이 있는 패턴 규칙 기능도 .class있습니다. 파일의 일부 영리한 사용과 그 결합 / 텍스트 기능이 좋아 $(wildcard), $(shell), $(eval)당신은 당신의 디렉토리 레이아웃에 분산 빌드 타겟을 발견하기 위해 makefile을 가르 칠 수 있습니다.
Tanz87

33

훌륭한 make프로그램은 C 및 C ++와 같이 별도로 컴파일 된 언어를 합리적으로 잘 처리합니다. 모듈을 컴파일하면 #include다른 포함 파일의 텍스트를 가져오고 단일 객체 파일을 출력으로 씁니다. 컴파일러는 객체 파일을 실행 가능한 이진 파일에 바인딩하기위한 별도의 연결 단계가있는 한 번에 하나의 시스템입니다.

그러나 Java에서는 컴파일러가 실제로 가져 오는 다른 클래스를 컴파일 해야합니다 import. Java 소스 코드에서 필요한 모든 종속성을 생성하여 make한 번에 하나씩 올바른 순서로 클래스를 빌드 하는 것을 작성할 수는 있지만 순환 종속성과 같은 경우는 처리하지 않습니다.

Java 컴파일러는 다른 클래스의 컴파일 된 결과를 캐싱하면서 이미 컴파일 된 클래스의 결과에 의존하는 추가 클래스를 컴파일함으로써보다 효율적일 수 있습니다. 이러한 종류의 자동 종속성 평가는 make단독으로 는 불가능합니다 .


7
이것은 make vs ant / maven 답변보다 make vs javac 답변처럼 보입니다. 당신의 대답에 따라 누군가 왜 make + javac를 사용할 수 없었습니까 (javac에 전체 패키지 또는 "모듈"을 한 번에 부여하면 순환 종속성이 make에서 숨겨져 있습니까?) 개미 또는 메이븐은 그 접근법에 비해 어떤 이점을 제공 할 것인가?
Laurence Gonsalves

1
@Laurence : javac에 한 번에 전체 패키지를 제공 할 수는 있지만 해당 패키지의 모든 것을 다시 컴파일 합니다 ( 그렇기 때문에 지시 한 것이므로). Java 컴파일러는 매우 빠르다는 것이 사실이지만, 무언가를 변경 한 후 다시 컴파일하는 데 필요한 클래스를 결정하면 더 빠릅니다.
Greg Hewgill

"main"클래스 만 컴파일하도록 javac에 지시 한 다음 의존하는 것을 자동으로 빌드하도록하는 것을 언급하고 있습니까? 마지막으로 (어쩌면 1.4에서 아마) 신뢰할 수없는 것을 확인했습니다. -Xdepend는 약간 나 았지만 (느려졌 고 여전히 깨졌습니다) 1.3에서 해당 플래그를 제거했습니다.
Laurence Gonsalves

4
또한, 이것은 왜 내가 왜 단순한 자바보다는 개미 또는 메이븐을 사용했는지 설명하지 못한다.
Laurence Gonsalves

28

이 질문은 잘못된 가정에 근거합니다. 사소한 수의 개발자 사용 make합니다. Java 빌드 도구 : Ant vs. Maven을 참조하십시오 . 왜 개발자 사용 하지 않는지에 관해서는 make: 많은 개발자들이 make그것을 사용 하지 않았 거나 그것을 사용하여 1000 태양보다 더 뜨거워지는 불로 그것을 미워했습니다. 따라서 대체 도구를 사용합니다.


10
우리는 그것을 사용하고, 불은 천 일 태양보다 더 뜨겁습니다.
초에 reccles

4
@ reccles : 빌드 엔지니어링이나 자체 제작에 대한 증오입니까? Ant, Maven 또는 다른 어떤 것이 더 좋을까요 (예 : 동급의 나쁜 도구를 만드는 것)?
사용자 1

5
@ User1 make에는 작성된 시점에 의미가있을 수있는 많은 "기능"이 있지만 이제는 버그와 비슷합니다. 예를 들어 특정 장소에서는 공백이 아닌 TAB 문자를 사용해야합니다. 그런 종류의 일은 실제로 경험이 많은 사람들을 귀찮게하지는 않지만 make나머지 사람들을 몰아냅니다.
행크 게이

4
@HankGuy : 편집자가 그 세부 사항에 대해 걱정하게하십시오. 편집기가 탭 <-> 공간 설정을 올바르게 처리 할 수없는 경우 새 편집기를 가져 오면 훨씬 행복해집니다. 그러나 동적 종속성을 처리하는 방식 ( make depend누군가) 과 같은 많은 기능이 오래되었다고 말하는 것은 옳습니다.
D.Shawley

3
@ User1 우리가 만들고있는 프로젝트의 규모입니다. 우리는 make 파일과 빌드 의존성을 유지하는 전임 직원이 있습니다. maven을 사용하면 더 관리하기 쉽다는 것을 알았습니다. 이제 maven도 완벽하지 않다고 말했습니다. 규정 된 설정과 약간 다른 빌드를 수행하는 데 필요한 XML 설정을 파악하는 것보다 더 화려하지는 않습니다.
reccles

28

실제로 make는 모든 오래된 Java 파일 중 하나의 명령으로 재 컴파일을 처리 할 수 ​​있습니다. 디렉토리의 모든 파일을 컴파일하지 않거나 특정 순서를 원하면 첫 번째 줄을 변경하십시오 ...

JAVA_FILES:=$(wildcard *.java)
#
# the rest is independent of the directory
#
JAVA_CLASSES:=$(patsubst %.java,%.class,$(JAVA_FILES))

.PHONY: classes
LIST:=

classes: $(JAVA_CLASSES)
        if [ ! -z "$(LIST)" ] ; then \
                javac $(LIST) ; \
        fi

$(JAVA_CLASSES) : %.class : %.java
        $(eval LIST+=$$<)

4
좋은! 나는 그런 것을 찾고있었습니다. 보편적 인 고전이 잘 작동 할 때 모든 언어에 대해 다른 빌드 도구를 사용할 필요가 없습니다. 감사!
rsp

17

각각의 기술적 장점에 대한 다른 모든 대답은 사실입니다. Ant그리고 Maven더 나은 메이크업보다 자바에 적합, 또는 행크 게이가 지적 하듯, 그들은하지 않을 수 있습니다 할 수있다 :

그러나 Ant와 Maven이 Java로 작성된 것이 중요한지 물었습니다. StackOverflow에서 우리는 그러한 생각 (닫힌! 프로그래밍과 관련이 없습니다! 등)을 고려하지 않습니다. 과정의 일부입니다. 레일에서는 Rake를 사용하고 C는 make를 사용하고 Java에서는 Ant와 Maven을 사용합니다. Ant 또는 Maven 개발자가 다른 개발자보다 Java 개발자를 더 잘 돌보는 것은 사실이지만, 또 다른 질문이 있습니다. Ant 태스크를 어떻게 작성합니까? 자바. Java 개발자라면 쉽게 맞을 수 있습니다.

예, 툴링 언어로 작성된 툴을 사용하는 것입니다.


7
Ant는 또한 Java 커뮤니티가 XML에 열광 할 때 일어났다. (XML에 장소가 없다고 말하는 것은 아닙니다.)
Laurence Gonsalves

3
@Laurence Gonsalves, 정말 그렇습니다. 그러나 제발, 우리는 여기서 유행에 대해 이야기하지 않습니다 :) 당시 Java 개발자를 가르치고 있었고 모든 것이 XML이었습니다. 이제는 여전히 XML이지만 아무도 신경 쓰지 않습니다.
Dan Rosenstark

1
툴링 주석은 흥미로운 것입니다. make유닉스 배경에서 나온 것이므로 툴링은 유용한 컴팩트 유틸리티를 작성하고 함께 파이프 라이닝하여 수행됩니다. 이것이 대부분의 스티칭이 쉘 명령을 사용하여 수행되는 이유입니다.
D.Shawley

2
@디. Shawley, make작은 유닉스 유틸리티 에 관한 모든 것 . GIT도 그 과정의 자식입니다. 개인적으로, 나는 그것이 더 좋지 않다고 말하지 않을 것입니다. 그러나 이것은 Java 프로그래머에게 큰 패러다임 전환입니다. Ant는 Java 사고 방식에 훨씬 더 적합합니다.
Dan Rosenstark 2019

12

Ant와 이후 Maven은 Make(프로세스에서 새로운 두통 을 만드는 동안) 발생하는 두통을 해결하도록 설계되었습니다 . 그것은 단지 진화 일뿐입니다.

... 그 후, 여러 오픈 소스 Java 프로젝트가 Ant가 Makefile과 관련된 문제를 해결할 수 있다는 것을 깨달았습니다.

에서 http://ant.apache.org/faq.html#history

그들이 무언가를 해결하거나 배우기 위해 여분의 형식을 만들지 여부는 주관적인 주제입니다. 진실은 모든 새로운 발명의 역사와 거의 같습니다. 제작자는 많은 문제를 해결하고 원래의 사용자는 이것이 미덕이라고 말합니다.

그것이 가진 주요 장점은 자바와 통합 할 수 있다는 것입니다.

rake예를 들어 비슷한 역사가있을 것입니다 .


4
그것은 구체적이지 않습니다. 메이븐은 어떤 두통으로 해결합니까?
Laurence Gonsalves

1
@Gonsalves : 모든 신기술의 주관적인 측면 중 하나 인 대안의 제작자는 많은 문제를 해결하고 교체 된 기술의 제작자는 이것이 결함이 아니라 미덕이라고 말합니다. 이 특별한 상황에서 자바 통합과 크로스 컴파일은 즉시 가능하다고 생각합니다
OscarRyz

2
[가장 최근의 의견이 아니라 답변 편집을 참조하십시오.] 여전히 어떤 문제가 해결되었는지 설명하지 않고, 제작자 개미는 문제가 해결되었다고 주장 할뿐입니다 ... :-/ 내 인상은 Ant가 처음에 Make의 간단한 대안이 되십시오. 시간이 지남에 따라 사람들은 누락 된 것들이 있음을 발견했으며 Ant가 make처럼 복잡해질 때까지 기능을 추가했지만 binutils가 내장되어 있습니다 (cp, rm 등과 같은 외부 도구에 크게 의존합니다). 물론 XML 구문이 있습니다.
Laurence Gonsalves

2
그렇습니다. 그러나 새로운 대안을 만든 사람이 할 수있는 최선의 방법은 "이것은 이전의 문제를 해결합니다"라고 말하는 것입니다. Ant는 내가 만든 문제를 해결합니까 , 아니면 새로운 문제를 소개하면서 문제로 생각하지 않는 것을 해결합니까?
Laurence Gonsalves

9

메이븐 (및 아이비 가능 앤트 설정)이 메이크를 통해 해결 한 주요 문제 중 하나는 자동 의존성 해결 및 의존성 jar 다운로드입니다.


6

가장 중요한 설명은 몇 가지 요소가 중요한시기 (1990 년대 후반)에 Java 커뮤니티 내에서 make를 사용하지 못하게했다는 것입니다.

  1. Java는 여러 플랫폼을 포함하므로 일반적으로 Java 프로그래머는 Unix 환경에 한정된 프로그래머 (예 : C 및 Perl 프로그래머)만큼 Unix 도구에 능숙하지 않았습니다. 이것은 일반적입니다. 의심 할 여지없이 유닉스에 대한 깊은 이해를 가진 Java 프로그래머가 있습니다.
  2. 결과적으로 그들은 제작에 익숙하지 않았고, 효과적으로 make를 사용하는 방법을 몰랐습니다.
  3. Java를 효율적으로 컴파일하는 짧고 간단한 Makefile을 작성할 수 있지만 플랫폼 독립적 인 방식으로 추가주의를 기울여야합니다.
  4. 따라서 본질적으로 플랫폼 독립적 인 빌드 도구에 대한 요구가있었습니다.
  5. 이 환경에서 Ant와 이후 Maven이 만들어졌습니다.

간단히 말해서 make가 Java 프로젝트에 가장 확실하게 사용될 수는 있지만 사실상 Java 빌드 도구로 만들 기회가있었습니다. 그 순간이 지났습니다.


5

스크립트는 본질적으로 플랫폼에 의존하는 경향이 있습니다. Java는 플랫폼 독립적이어야합니다. 따라서 다중 플랫폼 소스베이스에 대해 하나의 플랫폼에서만 작동하는 빌드 시스템을 갖는 것은 일종의 문제입니다.


5

짧은 대답 : make좋지 않기 때문입니다. C 전선에서도 많은 대안이 나타납니다.

긴 대답 : makeC 컴파일에는 거의 적합하지 않으며 Java 컴파일에는 전혀 적합하지 않은 몇 가지 결함이 있습니다. 원하는 경우 Java를 강제로 컴파일하도록 할 수 있지만 문제에 부딪 칠 것으로 예상되는데 그 중 일부에는 적합한 솔루션이나 해결 방법이 없습니다. 몇 가지가 있습니다 :

의존성 해결

make본질적으로 파일은 서로에 대해 트리와 같은 종속성을 가질 것으로 기대합니다. 한 파일은 여러 다른 파일을 빌드 한 결과입니다. 헤더 파일을 다룰 때 C에서 이미 역효과를냅니다. make필요 make후자에 변화가 이전에 재건 원인이 될 것이다, 그래서 파일을 포함 특이, 그 헤더 파일에 C 파일의 의존성을 표현하기 위해 생성 할 수 있습니다. 그러나 C 파일 자체는 재 작성되지 않고 (단순히 재 빌드되기 때문에) 대상을로 지정해야하는 경우가 종종 .PHONY있습니다. 다행히 GCC는 이러한 파일을 자동으로 생성하도록 지원합니다.

Java에서 종속성은 순환적일 수 있으며 make형식으로 클래스 종속성을 자동 생성하기위한 도구가 없습니다 . antDepend대신에, 클래스 파일을 읽을 수있는 작업은 직접, 어떤 클래스 그것을 수입을 결정하고, 그 중 하나가 구식 인 경우 클래스 파일을 삭제합니다. 이것이 없으면 사소하지 않은 종속성으로 인해 반복적 인 클린 빌드를 사용해야하므로 빌드 도구를 사용할 때의 이점이 사라집니다.

파일 이름의 공백

Java 나 C는 소스 코드 파일 이름에 공백을 사용하도록 권장하지 않지만 make공백이 파일 경로에 있어도 문제가 될 수 있습니다. 예를 들어 소스 코드가에있는 경우를 고려하십시오 C:\My Documents\My Code\program\src. 이것으로 충분합니다 make. make파일 이름을 문자열로 취급 하기 때문 입니다. ant경로를 특수 객체로 취급합니다.

빌드 할 파일 스캔

make각 대상에 대해 빌드 할 파일을 명시 적으로 설정해야합니다. ant소스 파일을 자동 검색 할 폴더를 지정할 수 있습니다. 약간의 편의처럼 보이지만 Java에서는 새 클래스마다 새 파일이 필요하다는 것을 고려하십시오. 프로젝트에 파일을 추가하는 것은 큰 번거 로움이 될 수 있습니다.

그리고 가장 큰 문제 make:

POSIX에 의존합니다

Java의 모토는 "한 번 실행하면 어디서나 컴파일"입니다. 그러나 Java 지원이 실제로 최악 인 POSIX 기반 시스템으로 컴파일을 제한하는 것은 의도가 아닙니다.

빌드 규칙 make은 본질적으로 작은 bash스크립트입니다. makeWindows에 대한 포트가 있지만 제대로 작동하려면 bash파일 시스템의 POSIX 에뮬레이션 계층을 포함하는 포트와 함께 번들로 묶어야합니다.

이것은 두 가지 종류가 있습니다.

  1. MSYS POSIX 변환을 파일 경로로 제한하려고 시도하기 때문에 특별히 만들어지지 않은 외부 도구를 실행할 때 불쾌한 문제가 발생할 수 있습니다.

  2. cygwin완전한 POSIX 에뮬레이션을 제공합니다. 그러나 결과 프로그램은 여전히 ​​해당 에뮬레이션 계층에 의존하는 경향이 있습니다.

이러한 이유로 Windows에서 표준 빌드 도구는 전혀 make없지만 MSBuildXML 기반 도구이기도하며 원칙적으로에 가깝습니다 ant.

반대로, antJava로 빌드되어 어디서나 실행할 수 있으며 플랫폼 독립적 인 방식으로 파일을 조작하고 명령을 실행하기위한 "작업"이라는 내부 도구를 포함합니다. 를 사용하는 ant것보다 Windows를 사용하여 C 프로그램을 작성하는 데 실제로 더 쉬운 시간을 가질 수있을 정도로 충분히 다재다능합니다 make.

그리고 마지막 작은 하나 :

C 프로그램조차도 기본적으로 make를 사용하지 않습니다

처음에는이를 알지 못할 수도 있지만 C 프로그램은 일반적으로로 제공되지 않습니다 Makefile. 이들은 실제 또는를 생성 CMakeLists.txt하는 bash구성 스크립트 와 함께 제공됩니다 Makefile. 반대로, 사용하여 빌드 된 Java 프로그램의 소스는 사전 빌드 antant스크립트 와 함께 제공됩니다 . A Makefile는 다른 도구의 제품입니다. 즉 make, 자체 빌드 도구로는 적합하지 않습니다. ant독립형이며 추가 요구 사항이나 종속성없이 Java 빌드 프로세스에 필요한 모든 것을 처리합니다.

ant모든 플랫폼에서 실행 하면 Just Works (tm)입니다. 당신은 그것을 얻을 수 없습니다 make. 엄청나게 플랫폼과 구성에 따라 다릅니다.


4

내가 아무도 아니라면 Java를 위해 make를 사용하는 사람이 없다고 가정하지 않습니다.

"GNU Make로 프로젝트 관리하기"(GFDL에서 사용 가능)에는 makeJava 프로젝트와 함께 사용하기위한 완전한 장이 포함되어 있습니다.

다른 도구 대신 make를 사용하는 장단점 목록이 포함되어 있으므로 여기에서 살펴볼 수 있습니다. ( http://oreilly.com/catalog/make3/book/ 참조 )


이것이 정확한 요약입니까? 확인 (다양한 맛) for Java를 사용할 수 있지만 약간의 통증. AntMaven (및 jmake ?)은 Java 프로젝트를보다 빠르고 쉽게 빌드 할 수 있도록 Java가 필요로하는 특별한 작업을 수행합니다. 또한 Java 이외의 프로젝트에 대해 플랫폼 독립적 빌드 프로세스에 사용할 수 있지만 Java에 맞게 조정됩니다.
Phil Perry

3

Ant는 Makefile에 비해 XML 구성 지향적 개선이며 Maven은 Ant에 대한 종속성 빌드 도구 개선입니다. 일부 프로젝트는 세 가지를 모두 사용합니다. JDK 프로젝트가 makefile과 개미를 혼합하여 사용했다고 생각합니다.


1

Ant 및 Maven (및 대부분의 Java 대상 SCM, CI 및 IDE 도구)이 Java 개발자 용 / Java 개발자 용으로 작성된 것이 가장 큰 이유입니다. 따라서 개발 환경에보다 쉽게 ​​통합 할 수 있으며 IDE 및 CI 서버와 같은 다른 도구를 사용하여 개미 / 메이븐 라이브러리의 일부를 빌드 / 배포 인프라 내에 통합 할 수 있습니다.


1

옛날 옛적에 나는 gmake를 사용하는 Java 프로젝트에서 일했다. 내 기억은 흐릿하지만 IIRC는 javac이 기대하는 패키지 디렉토리 구조를 다루는 데 어려움을 겪었습니다. 또한 JAR 파일을 작성하는 것이 사소한 것이 아니라면 번거 롭다는 것을 기억합니다.


1

ApacheAnt는 Make와는 다릅니다. Make는 파일 간의 종속성을 설명하고 파일을 작성하는 방법에 관한 것입니다. Ant는 "태스크"간의 종속성에 관한 것이며 빌드 스크립트를 함께 붙이는 방법에 더 가깝습니다.

AntVsMake에 도움이 될 수 있습니다


다운 보트의 이유에 대해 정말로 알고 싶습니다.
hagello

0

Ant와 Maven은 좀 더 '현대적인'관점에서 빌드 의존성 그래프와 관리에 접근합니다 ... 그러나 Oscar가 말했듯이, 그들은 make와 관련된 오래된 문제를 해결하려고 시도하면서 그들 만의 문제를 만들었습니다.


0

Java 용 GNU Make 프로젝트를 사용한 적이 없지만 jmk 를 사용 했습니다 . 안타깝게도 2002 년 이후로 업데이트되지 않았습니다.

Java 고유의 ​​기능이 있지만 크기를 크게 늘리지 않으면 서 소스 tarball에 포함시킬 정도로 작았습니다.

요즘에는 코드를 공유하는 Java 개발자가 Ant가 설치되어 있다고 가정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.