User Tools

Site Tools


lecture:clojure:프로젝트

Leiningen을 이용한 프로젝트 관리 및 emacs와의 연동

lein & project

이제 Clojure 개발 환경에 필요한 프로그램들을 모두 설치했으니, Clojure 프로젝트 관리 도구인 lein을 이용해, 간단한 프로젝트를 만들어 실행해 보자. lein이 하는 일을 비유를 통해 설명하자면, 리눅스에서 make와 apt-get이 하는 일을 합쳐 놓은 것과 유사하다. 즉, lein은 make처럼 프로젝트 컴파일과 관련된 일을 수행하면서, 동시에 개발에 필요한 라이브러리들을 의존성을 확인해 자동으로 다운로드해 주는 등, 기타 잡다한 다양한 일들을 프로그래머를 대신해 처리해 주는 편리한 도구이다.

lein 개관

자신이 작업하기 원하는 폴더(여기서는 C:\work)의 도스창을 띄운 후, lein version 명령을 입력해 설치된 버전을 확인해 보자.

C:\work> lein version
Leiningen 2.0.0-SNAPSHOT on Java 1.7.0_07 Java HotSpot(TM) Client VM

다음과 같이 입력하면 lein으로 할 수 있는 모든 작업들을 확인할 수 있다.

C:\work> lein
Leiningen is a tool for working with Clojure projects.

Several tasks are available:
check               Check syntax and warn on reflection.
classpath           Write the classpath of the current project to output-file.
clean               Remove all files from project's target-path.
compile             Compile Clojure source into .class files.
deploy              Build jar and deploy to remote repository.
deps                Show details about dependencies.
do                  Higher-order task to perform other tasks in succession.
help                Display a list of tasks or help for a given task.
install             Install current project to the local repository.
jar                 Package up all the project's files into a jar file.
javac               Compile Java source files.
new                 Generate project scaffolding based on a template.
plugin              DEPRECATED. Please use the :user profile instead.
pom                 Write a pom.xml file to disk for Maven interoperability.
repl                Start a repl session either with the current project or standalone.
retest              Run only the test namespaces which failed last time around.
run                 Run the project's -main function.
search              Search remote maven repositories for matching jars.
show-profiles       List all available profiles or display one if given an argument.
test                Run the project's tests.
trampoline          Run a task without nesting the project's JVM inside Leiningen's.
uberjar             Package up the project files and all dependencies into a jar file.
upgrade             Upgrade Leiningen to specified version or latest stable.
version             Print version for Leiningen and the current JVM.
with-profile        Apply the given task with the profile(s) specified.

Run lein help $TASK for details.

See also: readme, faq, tutorial, news, sample, profiles,
deploying and copying.

project의 생성

lein new 명령을 통해 myproject라는 이름의 새로운 프로젝트를 생성한다.

C:\work> lein new myproject
Generating a project called myprojec based on the 'default' template.
To see other templates (app, lein plugin, etc), try `lein help new`.

새로운 프로젝트는 myproject라는 새로운 폴더 밑에 다음과 같은 구조로 생성된다.

C:\work> cd myproject

C:\work\myproject> tree /a /f
C:.
|   .gitignore
|   project.clj
|   README.md
|
+---doc
|       intro.md
|
+---src
|   \---myproject
|           core.clj
|
\---test
    \---myproject
            core_test.clj

새로 생성된 파일 project.clj를 열면, 다음과 같은 내용이 보일 것이다.

(defproject myproject "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]])

위와 같은 파일 내용을 다음과 같이 수정해 준다.

(defproject myproject "0.1.0-SNAPSHOT"
  :description "My First Project in Clojure"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/tools.nrepl "0.2.3"]])
  • :dependencies — 현재의 프로젝트를 수행하는데 필요한 라이브러리들을 지정한다.

의존 라이브러리 다운로드

lein deps 명령을 수행하면, project.clj의 :dependencies 지정된 라이브러리를 다운로드할 뿐만 아니라, 그 지정된 라이브러리가 또 다른 라이브러리를 추가로 필요로 하는 지의 의존성을 확인해, 필요한 경우 관련된 모든 라이브러리를 자동으로 내려 받는다.

C:\work\myproject> lein deps

코드의 작성

src\myproject\core.clj 파일에, 표준 출력에 “Hello World!” 문자열을 출력하게 하는 코드를 다음과 같이 입력한다.

(ns myproject.core
  (:gen-class))
 
(defn -main [& args]
  (println "Hello world!"))

실행하기

lein run 명령을 통해 프로그램을 실행해 보자.

C:\work\myproject> lein run
No :main namespace specified in project.clj.
<code>

실행이 되지 않고 에러 메시지가 나왔다. project.clj 파일 안에 :main 관련 부분이 빠져있기 때문이다. :main 관련 부분에는, -main 함수가 정의되어 있는 nameaspace를 지정해 주어야 한다. src/myproject/core.clj에 -main함수가 정의되어 있으므로 project.clj 파일을 다음과 같이 수정해 준다.

<code>
(defproject myproject "0.1.0-SNAPSHOT"
  :description "My First Project in Clojure"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/tools.nrepl "0.2.3"]]
  :main myproject.core)

이제 다시 실행해 보자.

C:\work\myproject> lein run
Hello world!

원하는 결과가 출력되었다. 비로소 성공이다! 비록 간단한 프로젝트 예제이기는 하지만, lein으로 Clojure 프로젝트를 관리하는 기본적인 방법을 파악했으리라 믿는다.

그럼 이번에는 java.exe를 직접 호출해 실행하고 싶으면 어떻게 해야 할까? 간단히 다음과 같이 하면 된다.

C:\work\myproject> lein uberjar
Created C:\work\myproject\target\myproject-0.1.0-SNAPSHOT.jar
Including myproject-0.1.0-SNAPSHOT.jar
Including tools.nrepl-0.2.3.jar
Including clojure-1.4.0.jar
Created C:\temp\temp2\myproject\target\myproject-0.1.0-SNAPSHOT-standalone.jar

C:\work\myproject> cd target

C:\work\myproject\target> dir/w
myproject-0.1.0-SNAPSHOT-standalone.jar
myproject-0.1.0-SNAPSHOT.jar

C:\work\myproject\target> java -jar myproject-0.1.0-SNAPSHOT-standalone.jar
Hello world!

lein uberjar 명령은, java.exe에서 실행 가능한 형태로 프로젝트를 묶어, jar 파일을 생성한다.

라이브러리 검색하기

내려 받기 원하는 라이브러리 관련 정보를, 검색어를 통해 미리 살펴 볼 수 있다. lein search 명령을 실행하면, 각 관련 라이브러리의 버전별 정보가 출력되므로, 어떤 버전을 내려 받아야 하는지 판단하는데 도움이 된다.

최초로 lein search 명령을 내리면, http://clojars.org/repohttp://repo1.maven.org/maven2에서 라이브러리 인덱스 전체를 내려 받는데, 꽤 오랜 시간(본인의 경우에는 약 10분 정도)이 소요되므로, 느긋한 마음으로 기다려야 한다. 내려 받은 인덱스 관련 파일들은 C:\lang\leiningen\bin\indices\ 폴더 아래에 저장되는데 약 170 MB 크기이다.

C:\work\myproject> lein search ring
Downloading index from central - http://repo1.maven.org/maven2 ... this may take
 a while.

일단 인덱스 파일을 내려 받고 나면, 그 인덱스 파일을 대상으로 lein search 명령이 실행된다.

C:\work\myproject> lein search ring
 == Results from clojars - Showing page 1 / 29 total
[org.clojars.rnewman/ring "0.1.1-SNAPSHOT"] A Clojure web applications library.
[org.clojars.rnewman/ring "0.2.1-sessions"] A Clojure web applications library.
[org.clojars.rnewman/ring "0.2.2-sessions"] A Clojure web applications library.
[ring "0.1.1-SNAPSHOT"] A Clojure web applications library.
[ring "0.2.0"] A Clojure web applications library.
[ring "0.2.0-RC2"] A Clojure web applications library.
[org.clojars.paraseba/ring "0.2.0"] A Clojure web applications library.
[ring "0.2.1"] A Clojure web applications library.
[ring "0.2.2"] A Clojure web applications library.
[ring "0.2.3"] A Clojure web applications library.

위의 출력된 메시지를 보면, 총 29 페이지 분량 중 첫 페이지 분량만 출력됐음을 알 수 있다. 다음과 같이 보고자 하는 페이지 숫자를 입력하면, 뒤에 위치한 페이지도 볼 수 있다.

C:\work\myproject> lein search ring 2
 == Results from clojars - Showing page 2 / 29 total
[ring "0.2.4"] A Clojure web applications library.
[ring "0.2.5"] A Clojure web applications library.
[ring "0.3.0-beta1"] A Clojure web applications library.
[ring "0.2.6"] A Clojure web applications library.
[ring "0.3.0-RC1"] A Clojure web applications library.
[ring "0.3.0-RC2"] A Clojure web applications library.
[ring "0.3.0"] A Clojure web applications library.
[ring "0.3.1"] A Clojure web applications library.
[ring "0.3.2"] A Clojure web applications library.
[ring "0.3.3"] A Clojure web applications library.

인덱스 파일 자체를 가끔씩은 새로 내려받아야 할 필요가 있을 것이다. 이 경우에는 다음의 명령을 실행하도록 한다. 다만, 처음 인덱스 파일을 다운로드 받을 때처럼 시간이 아주 오래 걸리므로, 자주 실행하는 것은 바람직하지 않다.

C:\work\myproject> lein search --update

classpath의 확인

자바 프로그램을 실행하기 위해서는 먼저 classpath를 제대로 지정해 주어야 한다. 다행히도 lein은 프로젝트 개발에 필요한 classpath 경로를 자동으로 관리해 준다. 지금까지 작업을 진행하면서, lein이 자동으로 관리해 주고 있는 classpath를 확인해 보자.

C:\work\myproject> lein classpath
C:\work\myproject\test;C:\work\myproject\src;C:\work\myproject
\dev-resources;C:\work\myproject\resources;C:\work\myproject\target\
classes;C:\Users\philos\.m2\repository\org\clojure\tools.nrepl\0.2.3\tools
.nrepl-0.2.3.jar;C:\Users\philos\.m2\repository\org\clojure\clojure\1.4.0\
clojure-1.4.0.jar

출력 결과가 너무 복잡해 보여, 다음과 같이 보기 좋게 정리해 보았다.

C:\work\myproject\test;
C:\work\myproject\src;
C:\work\myproject\dev-resources;
C:\work\myproject\resources;
C:\work\myproject\target\classes;
C:\Users\philos\.m2\repository\org\clojure\tools.nrepl\0.2.3\tools.nrepl-0.2.3.jar;
C:\Users\philos\.m2\repository\org\clojure\clojure\1.4.0\clojure-1.4.0.jar

경우에 따라서는, lein이 자동으로 설정해 주는 classpath 이외에, 자신이 특별히 원하는 경로를 classpath에 추가하고 싶은 경우도 있을 것이다. 이럴 떄는 project.clj의 :extra-classpath-dirs 부분에 자신이 원하는 경로들을 다음과 같이 추가해 준다.

(defproject myproject "0.1.0-SNAPSHOT"
  :description "My First Project in Clojure"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/tools.nrepl "0.2.3"]]
  :main myproject.core
  :extra-classpath-dirs ["C:\\mylib\\tools.jar" "C:\\mylib\\utils.jar"])

lein & emacs

lein 하나만으로도 프로젝트를 관리할 수는 있겠지만, emacs와 연동시켜 작업하면 훨씬 작업이 수월해진다. emacs와의 연동에 필요한 프로그램들은 이미 앞에서 다운받아 놓은 상태이므로, 구체적으로 어떻게 연동하는지와, 알아 두면 유용한 프로그램밍 팁을 몇 가지 소개하겠다.

emacs와 nrepl.el의 연동

다음 그림은, C:\work\myproject\core.clj를 emacs로 불러 들인 후, 코드 몇 줄을 간단히 추가한 상태의 그림이다. Mode Line에 `(Clojure)' 라고 표시된 것에 주의하기 바란다. 확장자가 .clj로 끝나는 파일을 열면 자동으로 clojure-mode로 전환됨을 알 수 있다.

위의 상태에서 다음과 같이 입력한다. 여기에서 `M-x'는 `Alt-x' 키를 의미한다.

M-x nrepl-jack-in <Enter>

다음과 같이 2개의 화면으로 갈라지며, `user>' 프롬프트가 나오면 emacs와 nrepl의 연동에 성공한 것이다. 이 *nrepl* 버퍼에서, 다음 그림에서처럼, 다양한 clojure 코드를 테스트해 볼 수 있다.

*nrepl* 버퍼의 namespace 변경하기

아울러 *.clj 소스 버퍼에 커서를 갖다 놓은 후, C-c M-n 키를 누르면, 아래의 그림에서처럼 repl 버퍼의 namespace `user'가 clojure 소스 버퍼의 namespace `myproject.core'로 바뀐다.

소스 컴파일하기

위의 상태에서 C-c C-k 키를 누르면, 편집 중인 버퍼 전체를 컴파일할 수 있다. 이때 컴파일한 결과는 파일 형식으로 저장되는 것이 아니고 메모리상에서만 존재하므로, 파일 형태로 컴파일하고 싶으면 도스창에서 lein compile을 직접 실행해 주어야 한다.

다음 그림은 core.clj 버퍼에 커서를 갖다 놓은 후, C-c C-k 키를 눌러, core.clj 버퍼를 컴파일 한 후에, 컴파일한 코드들을 *nrepl* 버퍼에서 테스트하고 있는 모습이다.

또한 특정 함수의 코드 위에 커서를 갖다 놓은 후, C-M-x 키를 누르면, 그 특정 함수 하나만 메모리 상에서 컴파일 된다. 다른 프로그래밍 언어 사용자들은, 함수 하나만을, 그것도 메모리 상에서 컴파일한다고 하는 것이 이상하고 낯설게 느껴지겠지만, 리습 프로그래머들에게 이것은 너무나 자연스러운 일상이다.

clojure-mode와 nrepl.el에서 실행할 수 있는 기타 명령어들에 관한 자세한 내용은 https://github.com/kingtim/nrepl.el을 참고하기 바란다.

lecture/clojure/프로젝트.txt · Last modified: 2019/02/04 14:26 (external edit)